Vytváření vlastních ovládacích prvků v Xamarin.Macu

Při práci s C# a .NET v aplikaci Xamarin.Mac máte přístup ke stejným uživatelským ovládacím prvkům jako vývojář pracující v Objective-C nástroji Objective-C a Xcode. Vzhledem k tomu, že Xamarin.Mac se integruje přímo s Xcode, můžete použít Interface Builder Xcode k vytvoření a údržbě uživatelských ovládacích prvků (nebo je volitelně vytvořit přímo v kódu jazyka C#).

I když macOS poskytuje velké množství integrovaných uživatelských ovládacích prvků, možná budete muset vytvořit vlastní ovládací prvek, který bude poskytovat funkce, které nejsou k dispozici hned, nebo aby odpovídaly vlastnímu motivu uživatelského rozhraní (například hernímu rozhraní).

Příklad vlastního ovládacího prvku uživatelského rozhraní

V tomto článku projdeme základy vytváření znovu použitelného ovládacího prvku custom Uživatelské rozhraní v aplikaci Xamarin.Mac. Důrazně doporučujeme, abyste si nejprve prošli článek Hello, Mac, konkrétně oddíly Úvod do Xcode a Interface Builder a Výstupy a Akce, protože se zabývá klíčovými koncepty a technikami, které budeme v tomto článku používat.

Možná se budete chtít podívat i na část dokumentu Exposing C# classes / methods to Objective-CExposing C# classes / methods to Objective-C která vysvětluje příkazy a používané k připojení tříd jazyka C# k objektům a prvkům uživatelského RegisterExportObjective-C rozhraní.

Úvod do vlastních ovládacích prvků

Jak je uvedeno výše, může se zobrazit čas, kdy potřebujete vytvořit vlastní ovládací prvek Uživatelské rozhraní pro opětovné použití, který bude poskytovat jedinečné funkce pro uživatelské rozhraní aplikace Xamarin.Mac nebo vytvořit vlastní motiv uživatelského rozhraní (například herní rozhraní).

V těchto situacích můžete snadno dědit z nástroje a vytvořit vlastní nástroj, který lze přidat do uživatelského rozhraní aplikace prostřednictvím kódu jazyka C# nebo prostřednictvím Interface Builder NSControl Xcode. Děděním z vlastního ovládacího prvku se automaticky zobrazí všechny standardní funkce, které má integrovaný NSControl Uživatelské rozhraní Control (například NSButton ).

Pokud vlastní ovládací Uživatelské rozhraní zobrazuje jenom informace (například vlastní nástroj pro grafy a grafický nástroj), můžete chtít místo dědit z NSViewNSControl .

Bez ohledu na to, která základní třída se používá, jsou základní kroky pro vytvoření vlastního ovládacího prvku stejné.

V tomto článku vytvoříte vlastní komponentu překlopení přepínače, která poskytuje jedinečný Uživatelské rozhraní motiv a příklad vytvoření plně funkčního ovládacího prvku Custom Uživatelské rozhraní Control.

Sestavení vlastního ovládacího prvku

Vzhledem k tomu, že vlastní ovládací prvek, který vytváříme, bude reagovat na uživatelský vstup (kliknutí levým tlačítkem myši), dědíme z NSControl . Tímto způsobem bude mít náš vlastní ovládací prvek automaticky všechny standardní funkce, které má integrovaný ovládací prvek Uživatelské rozhraní Control a reaguje jako standardní ovládací prvek macOS.

V Visual Studio pro Mac otevřete projekt Xamarin.Mac, pro který chcete vytvořit vlastní ovládací Uživatelské rozhraní pro (nebo vytvořit nový). Přidejte novou třídu a volejte ji NSFlipSwitch :

Přidání nové třídy

Dále upravte třídu NSFlipSwitch.cs a udělejte, aby vypadala takto:

using Foundation;
using System;
using System.CodeDom.Compiler;
using AppKit;
using CoreGraphics;

namespace MacCustomControl
{
    [Register("NSFlipSwitch")]
    public class NSFlipSwitch : NSControl
    {
        #region Private Variables
        private bool _value = false;
        #endregion

        #region Computed Properties
        public bool Value {
            get { return _value; }
            set {
                // Save value and force a redraw
                _value = value;
                NeedsDisplay = true;
            }
        }
        #endregion

        #region Constructors
        public NSFlipSwitch ()
        {
            // Init
            Initialize();
        }

        public NSFlipSwitch (IntPtr handle) : base (handle)
        {
            // Init
            Initialize();
        }

        [Export ("initWithFrame:")]
        public NSFlipSwitch (CGRect frameRect) : base(frameRect) {
            // Init
            Initialize();
        }

        private void Initialize() {
            this.WantsLayer = true;
            this.LayerContentsRedrawPolicy = NSViewLayerContentsRedrawPolicy.OnSetNeedsDisplay;
        }
        #endregion

        #region Draw Methods
        public override void DrawRect (CGRect dirtyRect)
        {
            base.DrawRect (dirtyRect);

            // Use Core Graphic routines to draw our UI
            ...

        }
        #endregion

        #region Private Methods
        private void FlipSwitchState() {
            // Update state
            Value = !Value;
        }
        #endregion

    }
}

První věc, kterou si musíme všimnout o naší vlastní třídě v tom, že dědíme z a pomocí příkazu Register tuto třídu zpřístupňujeme do třídy NSControl a NSControlObjective-C Interface Builder:

[Register("NSFlipSwitch")]
public class NSFlipSwitch : NSControl

V následujících částech se podrobněji podíváme na zbytek výše uvedeného kódu.

Sledování stavu ovládacího prvku

Vzhledem k tomu, že náš vlastní ovládací prvek je přepínač, potřebujeme způsob, jak sledovat stav zapnutí/vypnutí přepínače. Tento postup zřídíme pomocí následujícího kódu v NSFlipSwitch souboru :

private bool _value = false;
...

public bool Value {
    get { return _value; }
    set {
        // Save value and force a redraw
        _value = value;
        NeedsDisplay = true;
    }
}

Když se stav přepínače změní, potřebujeme způsob, jak aktualizovat uživatelské rozhraní. To uděláme tak, že ovládací prvek vynutíme překreslením uživatelského rozhraní pomocí NeedsDisplay = true .

Pokud náš ovládací prvek vyžadoval více než jeden stav On/Off (například více stavový přepínač se 3 pozicemi), mohli bychom ke sledování stavu použít výčet. V našem příkladu to bude jednoduché.

Přidali jsme také pomocnou metodu pro prohození stavu přepínače mezi přepínačem On (Zapnout) a Off (Vypnuto):

private void FlipSwitchState() {
    // Update state
    Value = !Value;
}

Později tuto pomocná třídu rozbalíme, aby informovala volajícího o změně stavu přepínačů.

Kreslení rozhraní ovládacího prvku

Rutiny kreslení základní grafiky použijeme k vykreslování vlastního ovládacího prvku Uživatelské rozhraní za běhu. Než to uděláme, musíme pro ovládací prvek zapnout vrstvy. Používáme k tomu následující privátní metodu:

private void Initialize() {
    this.WantsLayer = true;
    this.LayerContentsRedrawPolicy = NSViewLayerContentsRedrawPolicy.OnSetNeedsDisplay;
}

Tato metoda se volá z každého konstruktoru ovládacího prvku, aby se zajistilo, že je ovládací prvek správně nakonfigurovaný. Například:

public NSFlipSwitch (IntPtr handle) : base (handle)
{
    // Init
    Initialize();
}

Dále musíme přepsat metodu a přidat DrawRect rutiny základního obrázku, které nakreslí ovládací prvek:

public override void DrawRect (CGRect dirtyRect)
{
    base.DrawRect (dirtyRect);

    // Use Core Graphic routines to draw our UI
    ...

}

Vizuální reprezentaci ovládacího prvku upravíme, když se změní jeho stav (například změníme nastavení z On (Vypnuto) na On (Vypnuto). Kdykoli se stav změní, můžeme pomocí příkazu vynutit překreslení ovládacího prvku NeedsDisplay = true pro nový stav.

Reakce na vstup uživatele

Existují dva základní způsoby, jak do vlastního ovládacího prvku přidat uživatelský vstup: Override Mouse Handling Routines (Přepsat rutiny zpracování myši) nebo Gesture Recognizers (Rozpoznávání gest). Metoda, kterou použijeme, bude založená na funkcích, které vyžaduje náš ovládací prvek.

Důležité

U každého vlastního ovládacího prvku, který vytvoříte, byste měli použít buď metody přepsání, nebo rozpoznávání gest,ale ne obojí současně, protože mohou být vzájemně v konfliktu.

Zpracování uživatelského vstupu pomocí metod přepsání

Objekty, které dědí z nebo , mají několik metod přepsání pro NSControl zpracování vstupu myši nebo NSView klávesnice. U našeho příkladu ovládacího prvku chceme překlopit stav přepínače mezi zapnutím a vypnutím, když uživatel klikne na ovládací prvek levým tlačítkem myši. Ke zpracování můžeme do třídy přidat následující metody NSFlipSwitch přepsání:

#region Mouse Handling Methods
// --------------------------------------------------------------------------------
// Handle mouse with Override Methods.
// NOTE: Use either this method or Gesture Recognizers, NOT both!
// --------------------------------------------------------------------------------
public override void MouseDown (NSEvent theEvent)
{
    base.MouseDown (theEvent);

    FlipSwitchState ();
}

public override void MouseDragged (NSEvent theEvent)
{
    base.MouseDragged (theEvent);
}

public override void MouseUp (NSEvent theEvent)
{
    base.MouseUp (theEvent);
}

public override void MouseMoved (NSEvent theEvent)
{
    base.MouseMoved (theEvent);
}
## endregion

Ve výše uvedeném kódu voláme metodu (definovanou výše), která převrátí stav přepínače v FlipSwitchStateMouseDown metodě . Tím se také vynutí překreslit ovládací prvek tak, aby odrážel aktuální stav.

Zpracování uživatelského vstupu pomocí rozpoznávání gest

Volitelně můžete použít rozpoznávání gest ke zpracování interakcí uživatele s ovládacím prvku. Odeberte přepsání přidaná výše, upravte metodu a Initialize zajistěte, aby vypadala takto:

private void Initialize() {
    this.WantsLayer = true;
    this.LayerContentsRedrawPolicy = NSViewLayerContentsRedrawPolicy.OnSetNeedsDisplay;

    // --------------------------------------------------------------------------------
    // Handle mouse with Gesture Recognizers.
    // NOTE: Use either this method or the Override Methods, NOT both!
    // --------------------------------------------------------------------------------
    var click = new NSClickGestureRecognizer (() => {
        FlipSwitchState();
    });
    AddGestureRecognizer (click);
}

Tady vytváříme novou metodu a voláme metodu , která změní stav přepínače, když na něj uživatel klikne NSClickGestureRecognizerFlipSwitchState levým tlačítkem myši. Metoda AddGestureRecognizer (click) přidá do ovládacího prvku Rozpoznávání gest.

To, kterou metodu používáme, opět závisí na tom, čeho se snažíme pomocí vlastního ovládacího prvku dosáhnout. Pokud potřebujeme přístup nízké úrovně k interakci s uživatelem, použijte metody přepsání. Pokud potřebujeme předdefinované funkce, jako jsou kliknutí myší, použijte Rozpoznávání gest.

Reakce na události změny stavu

Když uživatel změní stav vlastního ovládacího prvku, potřebujeme způsob, jak reagovat na změnu stavu v kódu (například udělat něco po kliknutí na vlastní tlačítko).

Pokud chcete tuto funkci poskytnout, upravte NSFlipSwitch třídu a přidejte následující kód:

#region Events
public event EventHandler ValueChanged;

internal void RaiseValueChanged() {
    if (this.ValueChanged != null)
        this.ValueChanged (this, EventArgs.Empty);

    // Perform any action bound to the control from Interface Builder
    // via an Action.
    if (this.Action !=null)
        NSApplication.SharedApplication.SendAction (this.Action, this.Target, this);
}
## endregion

Dále upravte FlipSwitchState metodu a vytvořte, aby vypadala takto:

private void FlipSwitchState() {
    // Update state
    Value = !Value;
    RaiseValueChanged ();
}

Nejprve poskytneme událost, do které můžeme přidat obslužnou rutinu v kódu C#, abychom mohli provést akci, když uživatel změní ValueChanged stav přepínače.

Za druhé, protože náš vlastní ovládací prvek dědí z , má automaticky akci, kterou je možné přiřadit v souboru NSControl Interface Builder. NSControl K volání této akce při změně stavu použijeme následující kód:

if (this.Action !=null)
    NSApplication.SharedApplication.SendAction (this.Action, this.Target, this);

Nejprve zkontrolujeme, jestli byla k ovládacímu prvku přiřazena akce. Dále zavoláme akci , pokud byla definována.

Použití vlastního ovládacího prvku

Když máme vlastní ovládací prvek plně definovaný, můžeme ho buď přidat do uživatelského rozhraní aplikace Xamarin.Mac pomocí kódu jazyka C#, nebo v uživatelském rozhraní Interface Builder.

Pokud chcete ovládací prvek přidat pomocí Interface Builder, nejprve proveďte čisté sestavení projektu Xamarin.Mac a pak poklikejte na soubor a otevřete ho v Interface Builder Main.storyboard pro úpravy:

Úprava scénáře v Xcode

V dalším kroku Custom View přetáhněte do Uživatelské rozhraní návrhu:

Výběr vlastního zobrazení z knihovny

Když je vlastní zobrazení stále vybrané, přepněte do inspektoru identit a změňte třídu zobrazení na :

Nastavení třídy View

Přepněte do Editoru asistenta a vytvořte výstup pro vlastní ovládací prvek (nezapomeňte ho svázat v souboru, a ne v souboru):

Konfigurace nového výstupu

Uložte změny, vraťte se Visual Studio pro Mac a povolte synchronizaci změn. Upravte ViewController.cs soubor a ViewDidLoad zajistěte, aby metoda vypadala takto:

public override void ViewDidLoad ()
{
    base.ViewDidLoad ();

    // Do any additional setup after loading the view.
    OptionTwo.ValueChanged += (sender, e) => {
        // Display the state of the option switch
        Console.WriteLine("Option Two: {0}", OptionTwo.Value);
    };
}

Tady odpovíme na událost, která jsme ve třídě definovali výše, a když uživatel klikne na ovládací prvek, zapíšeme aktuální ValueChangedNSFlipSwitch hodnotu. ValueChanged

Volitelně se můžeme vrátit k Interface Builder a definovat akci u ovládacího prvku:

Konfigurace nové akce

Znovu upravte soubor ViewController.cs a přidejte následující metodu:

partial void OptionTwoFlipped (Foundation.NSObject sender) {
    // Display the state of the option switch
    Console.WriteLine("Option Two: {0}", OptionTwo.Value);
}

Důležité

Měli byste použít buď událost , nebo definovat akci v Interface Builder, ale neměli byste používat obě metody současně, jinak mohou být vzájemně v konfliktu.

Souhrn

Tento článek podrobně popisuje vytvoření znovu použitelného ovládacího prvku custom Uživatelské rozhraní v aplikaci Xamarin.Mac. Viděli jsme, jak nakreslit uživatelské rozhraní vlastních ovládacích prvků, dva hlavní způsoby reakce na vstup myši a uživatele a jak zveřejnit nový ovládací prvek pro akce v uživatelském rozhraní Interface Builder.