Benutzerdefinierte Steuerelemente im Xamarin-Designer für iOS

Das Xamarin-Designer für iOS unterstützt das Rendern benutzerdefinierter Steuerelemente, die in Ihrem Projekt erstellt wurden oder aus externen Quellen wie dem Xamarin-Komponentenspeicher referenziert werden.

Warnung

Der iOS Designer ist seit Visual Studio 2019, Version 16.8, und Visual Studio 2019 für Mac, Version 8.8, veraltet und wurde in Visual Studio 2019, Version 16.9, bzw. Visual Studio für Mac, Version 8.9, entfernt. Die empfohlene Möglichkeit zum Erstellen von iOS-Benutzeroberflächen ist direkt auf einem Mac mit Xcode. Weitere Informationen finden Sie unter Entwerfen von Benutzeroberflächen mit Xcode.

Xamarin Designer für iOS ist ein leistungsstarkes Tool zum Visualisieren der Benutzeroberfläche einer Anwendung und bietet WYSIWYG-Bearbeitungsunterstützung für die meisten iOS-Ansichten und Ansichtscontroller. Ihre App kann auch benutzerdefinierte Steuerelemente enthalten, die die in iOS integrierten Steuerelemente erweitern. Wenn diese benutzerdefinierten Steuerelemente unter Berücksichtigung einiger Richtlinien geschrieben werden, können sie auch vom iOS-Designer gerendert werden, was eine noch umfangreichere Bearbeitungserfahrung bietet. In diesem Dokument werden diese Richtlinien behandelt.

Anforderungen

Ein Steuerelement, das alle folgenden Anforderungen erfüllt, wird auf der Entwurfsoberfläche gerendert:

  1. Es ist eine direkte oder indirekte Unterklasse von UIView oder UIViewController. Andere NSObject-Unterklassen werden als Symbol auf der Entwurfsoberfläche angezeigt.
  2. Es verfügt über ein RegisterAttribute , um es für verfügbar zu machen Objective-C.
  3. Es verfügt über den erforderlichen IntPtr-Konstruktor.
  4. Entweder wird die IComponent-Schnittstelle implementiert oder ein DesignTimeVisibleAttribute auf True festgelegt.

In Code definierte Steuerelemente, die die oben genannten Anforderungen erfüllen, werden im Designer angezeigt, wenn ihr enthaltenes Projekt für den Simulator kompiliert wird. Standardmäßig werden alle benutzerdefinierten Steuerelemente im Abschnitt Benutzerdefinierte Komponenten der Toolbox angezeigt. Das CategoryAttribute kann jedoch auf die Klasse des benutzerdefinierten Steuerelements angewendet werden, um einen anderen Abschnitt anzugeben.

Das Laden von Bibliotheken von Drittanbietern Objective-C wird vom Designer nicht unterstützt.

Benutzerdefinierte Eigenschaften

Eine von einem benutzerdefinierten Steuerelement deklarierte Eigenschaft wird im Eigenschaftenbereich angezeigt, wenn die folgenden Bedingungen erfüllt sind:

  1. Die Eigenschaft verfügt über einen öffentlichen Getter und Setter.
  2. Die Eigenschaft verfügt über ein ExportAttribute sowie ein BrowsableAttribute , das auf True festgelegt ist.
  3. Der Eigenschaftstyp ist ein numerischer Typ, Enumerationstyp, string, bool, SizeF, UIColor oder UIImage. Diese Liste der unterstützten Typen kann in Zukunft erweitert werden.

Die Eigenschaft kann auch mit einem DisplayNameAttribute versehen sein, um die Bezeichnung anzugeben, die im Eigenschaftenbereich für sie angezeigt wird.

Initialisierung

Für UIViewController Unterklassen sollten Sie die ViewDidLoad-Methode für Code verwenden, der von Ansichten abhängt, die Sie im Designer erstellt haben.

Für UIView und andere NSObject Unterklassen ist die AwakeFromNib-Methode der empfohlene Ort, um die Initialisierung Ihres benutzerdefinierten Steuerelements durchzuführen, nachdem es aus der Layoutdatei geladen wurde. Dies liegt daran, dass alle benutzerdefinierten Eigenschaften, die im Eigenschaftenbereich festgelegt sind, nicht festgelegt werden, wenn der Konstruktor des Steuerelements ausgeführt wird. Sie werden jedoch festgelegt, bevor AwakeFromNib aufgerufen wird:

[Register ("CustomView"), DesignTimeVisible (true)]
public class CustomView : UIView {

    public CustomView (IntPtr handle) : base (handle) { }

    public override void AwakeFromNib ()
    {
        // Initialize the view here.
    }
}

Wenn das Steuerelement auch so konzipiert ist, dass es direkt aus Code erstellt wird, können Sie eine Methode erstellen, die über allgemeinen Initialisierungscode verfügt, wie folgt:

[Register ("CustomView"), DesignTimeVisible (true)]
public class CustomView : UIView {

    public CustomView (IntPtr handle) : base (handle) { }

    public CustomView ()
    {
        // Called when created from code.
        Initialize ();
    }

    public override void AwakeFromNib ()
    {
        // Called when loaded from xib or storyboard.
        Initialize ();
    }

    void Initialize ()
    {
        // Common initialization code here.
    }
}

Eigenschafteninitialisierung und AwakeFromNib

Es sollte darauf geachtet werden, wann und wo entwurfsfähige Eigenschaften in einer benutzerdefinierten Komponente initialisiert werden sollen, um werte, die innerhalb der iOS-Designer festgelegt wurden, nicht zu überschreiben. Nehmen Sie als Beispiel den folgenden Code:

[Register ("CustomView"), DesignTimeVisible (true)]
public class CustomView : UIView {

    [Export ("Counter"), Browsable (true)]
    public int Counter {get; set;}

    public CustomView (IntPtr handle) : base (handle) { }

    public CustomView ()
    {
        // Called when created from code.
        Initialize ();
    }

    public override void AwakeFromNib ()
    {
        // Called when loaded from xib or storyboard.
        Initialize ();
    }

    void Initialize ()
    {
        // Common initialization code here.
        Counter = 0;
    }
}

Die CustomView Komponente macht eine Counter Eigenschaft verfügbar, die vom Entwickler innerhalb der iOS-Designer festgelegt werden kann. Unabhängig davon, welcher Wert im Designer festgelegt wird, ist der Wert der Counter Eigenschaft immer 0 (0). Dies ist der Grund:

  • Eine instance von CustomControl wird aus der Storyboarddatei aufgeblasen.
  • Alle im iOS-Designer geänderten Eigenschaften werden festgelegt (z. B. festlegen des Werts Counter auf zwei (2).
  • Die AwakeFromNib -Methode wird ausgeführt, und die -Methode der Komponente Initialize wird aufgerufen.
  • Innerhalb Initialize des Werts der Counter Eigenschaft wird auf Null (0) zurückgesetzt.

Um die obige Situation zu beheben, initialisieren Sie entweder die Counter Eigenschaft an einer anderen Stelle (z. B. im Konstruktor der Komponente), oder überschreiben Sie die AwakeFromNib -Methode nicht, und rufen Sie auf Initialize , wenn die Komponente keine weitere Initialisierung außerhalb dessen erfordert, was derzeit von ihren Konstruktoren verarbeitet wird.

Entwurfsmodus

Auf der Entwurfsoberfläche muss ein benutzerdefiniertes Steuerelement einige Einschränkungen einhalten:

  • App-Bundleressourcen sind im Entwurfsmodus nicht verfügbar. Images sind verfügbar, wenn sie über uiImage-Methoden geladen werden.
  • Asynchrone Vorgänge, z. B. Webanforderungen, sollten nicht im Entwurfsmodus ausgeführt werden. Die Entwurfsoberfläche unterstützt keine Animationen oder andere asynchrone Updates für die Benutzeroberfläche des Steuerelements.

Ein benutzerdefiniertes Steuerelement kann IComponent implementieren und die DesignMode-Eigenschaft verwenden, um zu überprüfen, ob es sich auf der Entwurfsoberfläche befindet. In diesem Beispiel zeigt die Bezeichnung "Entwurfsmodus" auf der Entwurfsoberfläche und "Runtime" zur Laufzeit an:

[Register ("DesignerAwareLabel")]
public class DesignerAwareLabel : UILabel, IComponent {

    #region IComponent implementation

    public ISite Site { get; set; }
    public event EventHandler Disposed;

    #endregion

    public DesignerAwareLabel (IntPtr handle) : base (handle) { }

    public override void AwakeFromNib ()
    {
        if (Site != null && Site.DesignMode)
            Text = "Design Mode";
        else
            Text = "Runtime";
    }
}

Sie sollten die Site Eigenschaft null immer auf überprüfen, bevor Sie versuchen, auf eines ihrer Member zuzugreifen. Wenn Site dies der Wert ist null, kann davon ausgegangen werden, dass das Steuerelement im Designer nicht ausgeführt wird. Im Entwurfsmodus wird festgelegt, Site nachdem der Konstruktor des Steuerelements ausgeführt wurde und bevor AwakeFromNib aufgerufen wird.

Debuggen

Ein Steuerelement, das die oben genannten Anforderungen erfüllt, wird in der Toolbox angezeigt und auf der Oberfläche gerendert. Wenn ein Steuerelement nicht gerendert wird, suchen Sie nach Fehlern im Steuerelement oder einer seiner Abhängigkeiten.

Die Entwurfsoberfläche kann häufig Ausnahmen abfangen, die von einzelnen Steuerelementen ausgelöst werden, während andere Steuerelemente weiterhin gerendert werden. Das fehlerhafte Steuerelement wird durch einen roten Platzhalter ersetzt, und Sie können die Ausnahmeablaufverfolgung anzeigen, indem Sie auf das Ausrufesymbol klicken:

Ein fehlerhaftes Steuerelement als roter Platzhalter und die Ausnahmedetails

Wenn Debugsymbole für das Steuerelement verfügbar sind, weist die Ablaufverfolgung Dateinamen und Zeilennummern auf. Durch Doppelklicken auf eine Zeile in der Stapelablaufverfolgung wird zu dieser Zeile im Quellcode gesprungen.

Wenn der Designer das fehlerhafte Steuerelement nicht isolieren kann, wird oben auf der Entwurfsoberfläche eine Warnmeldung angezeigt:

Eine Warnmeldung am oberen Rand der Entwurfsoberfläche

Das vollständige Rendering wird fortgesetzt, wenn das fehlerhafte Steuerelement behoben oder von der Entwurfsoberfläche entfernt wird.

Zusammenfassung

In diesem Artikel wurde die Erstellung und Anwendung benutzerdefinierter Steuerelemente im iOS-Designer vorgestellt. Zunächst wurden die Anforderungen beschrieben, die Steuerelemente erfüllen müssen, um auf der Entwurfsoberfläche gerendert zu werden, und benutzerdefinierte Eigenschaften im Eigenschaftenbereich verfügbar machen. Anschließend wurde der Code Behind untersucht: Initialisierung des Steuerelements und der DesignMode-Eigenschaft. Zuletzt wurde beschrieben, was geschieht, wenn Ausnahmen ausgelöst werden, und wie dies behoben werden kann.