Udostępnij za pośrednictwem


Projekt interfejsu użytkownika .storyboard/.xib-less w środowisku Xamarin.Mac

W tym artykule opisano tworzenie interfejsu użytkownika aplikacji platformy Xamarin.Mac bezpośrednio z poziomu kodu języka C#, bez plików scenorysu, plików xib lub narzędzia Interface Builder.

Omówienie

Podczas pracy z językami C# i .NET w aplikacji platformy Xamarin.Mac masz dostęp do tych samych elementów interfejsu użytkownika i narzędzi, które wykonuje deweloper pracujący w Objective-C środowisku I Xcode . Zazwyczaj podczas tworzenia aplikacji platformy Xamarin.Mac użyjesz narzędzia Interface Builder środowiska Xcode z plikami .storyboard lub .xib, aby utworzyć i obsługiwać interfejs użytkownika aplikacji.

Istnieje również możliwość utworzenia interfejsu użytkownika aplikacji Xamarin.Mac bezpośrednio w kodzie języka C#. W tym artykule omówimy podstawy tworzenia interfejsów użytkownika i elementów interfejsu użytkownika w kodzie języka C#.

Edytor kodu Visual Studio dla komputerów Mac

Przełączanie okna w celu używania kodu

Podczas tworzenia nowej aplikacji platformy Xamarin.Mac Cocoa domyślnie zostanie wyświetlone standardowe puste okno. Te okna są definiowane w pliku Main.storyboard (lub tradycyjnie MainWindow.xib) automatycznie dołączonym do projektu. Obejmuje to również plik ViewController.cs , który zarządza głównym widokiem aplikacji (lub ponownie tradycyjnie MainWindow.cs i plikiem MainWindowController.cs ).

Aby przełączyć się do okna Xibless dla aplikacji, wykonaj następujące czynności:

  1. Otwórz aplikację, której chcesz przestać używać .storyboard plików lub xib, aby zdefiniować interfejs użytkownika w Visual Studio dla komputerów Mac.

  2. W okienku rozwiązania kliknij prawym przyciskiem myszy plik Main.storyboard lub MainWindow.xib i wybierz polecenie Usuń:

    Usuwanie głównego scenorysu lub okna

  3. W oknie dialogowym Usuń kliknij przycisk Usuń, aby całkowicie usunąć scenorys lub .xib z projektu:

    Potwierdzanie usunięcia

Teraz musimy zmodyfikować plik MainWindow.cs , aby zdefiniować układ okna i zmodyfikować plik ViewController.cs lub MainWindowController.cs , aby utworzyć wystąpienie klasy MainWindow , ponieważ nie używamy już pliku .storyboard lub xib.

Nowoczesne aplikacje platformy Xamarin.Mac korzystające z scenorysów dla interfejsu użytkownika mogą nie zawierać automatycznie plików MainWindow.cs, ViewController.cs ani MainWindowController.cs . W razie potrzeby wystarczy dodać nową pustą klasę języka C# do projektu (Dodaj>nowy plik...>Ogólna>pusta klasa) i nadaj jej nazwę tak samo jak brakujący plik.

Definiowanie okna w kodzie

Następnie zmodyfikuj plik MainWindow.cs i utwórz go w następujący sposób:

using System;
using Foundation;
using AppKit;
using CoreGraphics;

namespace MacXibless
{
    public partial class MainWindow : NSWindow
    {
        #region Private Variables
        private int NumberOfTimesClicked = 0;
        #endregion

        #region Computed Properties
        public NSButton ClickMeButton { get; set;}
        public NSTextField ClickMeLabel { get ; set;}
        #endregion

        #region Constructors
        public MainWindow (IntPtr handle) : base (handle)
        {
        }

        [Export ("initWithCoder:")]
        public MainWindow (NSCoder coder) : base (coder)
        {
        }

        public MainWindow(CGRect contentRect, NSWindowStyle aStyle, NSBackingStore bufferingType, bool deferCreation): base (contentRect, aStyle,bufferingType,deferCreation) {
            // Define the user interface of the window here
            Title = "Window From Code";

            // Create the content view for the window and make it fill the window
            ContentView = new NSView (Frame);

            // Add UI elements to window
            ClickMeButton = new NSButton (new CGRect (10, Frame.Height-70, 100, 30)){
                AutoresizingMask = NSViewResizingMask.MinYMargin
            };
            ContentView.AddSubview (ClickMeButton);

            ClickMeLabel = new NSTextField (new CGRect (120, Frame.Height - 65, Frame.Width - 130, 20)) {
                BackgroundColor = NSColor.Clear,
                TextColor = NSColor.Black,
                Editable = false,
                Bezeled = false,
                AutoresizingMask = NSViewResizingMask.WidthSizable | NSViewResizingMask.MinYMargin,
                StringValue = "Button has not been clicked yet."
            };
            ContentView.AddSubview (ClickMeLabel);
        }
        #endregion

        #region Override Methods
        public override void AwakeFromNib ()
        {
            base.AwakeFromNib ();

            // Wireup events
            ClickMeButton.Activated += (sender, e) => {
                // Update count
                ClickMeLabel.StringValue = (++NumberOfTimesClicked == 1) ? "Button clicked one time." : string.Format("Button clicked {0} times.",NumberOfTimesClicked);
            };
        }
        #endregion

    }
}

Omówimy kilka kluczowych elementów.

Najpierw dodaliśmy kilka obliczonych właściwości , które będą działać podobnie do gniazd (tak jak w przypadku utworzenia okna w pliku .storyboard lub xib):

public NSButton ClickMeButton { get; set;}
public NSTextField ClickMeLabel { get ; set;}

Zapewni to dostęp do elementów interfejsu użytkownika, które będą wyświetlane w oknie. Ponieważ okno nie jest zawyżone z pliku .storyboard lub .xib, musimy utworzyć wystąpienie tego okna (jak zobaczymy później w MainWindowController klasie). To właśnie robi ta nowa metoda konstruktora:

public MainWindow(CGRect contentRect, NSWindowStyle aStyle, NSBackingStore bufferingType, bool deferCreation): base (contentRect, aStyle,bufferingType,deferCreation) {
    ...
}

W tym miejscu zaprojektujemy układ okna i umieścimy wszystkie elementy interfejsu użytkownika potrzebne do utworzenia wymaganego interfejsu użytkownika. Aby można było dodać do okna dowolne elementy interfejsu użytkownika, musi on zawierać elementy w widoku zawartości:

ContentView = new NSView (Frame);

Spowoduje to utworzenie widoku zawartości, który wypełni okno. Teraz do okna dodamy nasz pierwszy element interfejsu użytkownika , , NSButton:

ClickMeButton = new NSButton (new CGRect (10, Frame.Height-70, 100, 30)){
    AutoresizingMask = NSViewResizingMask.MinYMargin
};
ContentView.AddSubview (ClickMeButton);

Pierwszą rzeczą, którą należy zauważyć, jest to, że w przeciwieństwie do systemu iOS system macOS używa notacji matematycznej do definiowania układu współrzędnych okna. Dlatego punkt początkowy znajduje się w lewym dolnym rogu okna, z wartościami rosnącymi w prawo i w prawym górnym rogu okna. Podczas tworzenia nowego NSButtonelementu bierzemy to pod uwagę podczas definiowania jego położenia i rozmiaru na ekranie.

Właściwość AutoresizingMask = NSViewResizingMask.MinYMargin informuje przycisk, że chcemy pozostać w tej samej lokalizacji w górnej części okna, gdy rozmiar okna zostanie zmieniony w pionie. Ponownie jest to wymagane, ponieważ (0,0) znajduje się w lewym dolnym rogu okna.

Na koniec metoda dodaje element NSButton do widoku zawartości, ContentView.AddSubview (ClickMeButton) aby był wyświetlany na ekranie po uruchomieniu aplikacji i wyświetlonym oknie.

Następnie do okna zostanie dodana etykieta, która będzie wyświetlać liczbę NSButton kliknięć:

ClickMeLabel = new NSTextField (new CGRect (120, Frame.Height - 65, Frame.Width - 130, 20)) {
    BackgroundColor = NSColor.Clear,
    TextColor = NSColor.Black,
    Editable = false,
    Bezeled = false,
    AutoresizingMask = NSViewResizingMask.WidthSizable | NSViewResizingMask.MinYMargin,
    StringValue = "Button has not been clicked yet."
};
ContentView.AddSubview (ClickMeLabel);

Ponieważ system macOS nie ma określonego elementu interfejsu użytkownika etykiety , dodaliśmy specjalnie stylizowany, nieedytowalny NSTextField element do działania jako etykieta. Podobnie jak poprzednio, rozmiar i lokalizacja uwzględniają, że (0,0) znajduje się w lewym dolnym rogu okna. Właściwość AutoresizingMask = NSViewResizingMask.WidthSizable | NSViewResizingMask.MinYMargin używa operatora or do łączenia dwóch NSViewResizingMask funkcji. Spowoduje to, że etykieta pozostanie w tej samej lokalizacji w górnej części okna, gdy rozmiar okna zostanie zmieniony w pionie i zmniejsza się i zwiększa szerokość, ponieważ rozmiar okna jest zmieniany w poziomie.

Ponownie metoda dodaje element NSTextField do widoku zawartości, ContentView.AddSubview (ClickMeLabel) aby był wyświetlany na ekranie po uruchomieniu aplikacji i otwarciu okna.

Dostosowywanie kontrolera okna

Ponieważ projekt elementu MainWindow nie jest już ładowany z pliku .storyboard lub .xib, musimy wprowadzić pewne zmiany w kontrolerze okien. Zmodyfikuj plik MainWindowController.cs i utwórz go w następujący sposób:

using System;

using Foundation;
using AppKit;
using CoreGraphics;

namespace MacXibless
{
    public partial class MainWindowController : NSWindowController
    {
        public MainWindowController (IntPtr handle) : base (handle)
        {
        }

        [Export ("initWithCoder:")]
        public MainWindowController (NSCoder coder) : base (coder)
        {
        }

        public MainWindowController () : base ("MainWindow")
        {
            // Construct the window from code here
            CGRect contentRect = new CGRect (0, 0, 1000, 500);
            base.Window = new MainWindow(contentRect, (NSWindowStyle.Titled | NSWindowStyle.Closable | NSWindowStyle.Miniaturizable | NSWindowStyle.Resizable), NSBackingStore.Buffered, false);

            // Simulate Awaking from Nib
            Window.AwakeFromNib ();
        }

        public override void AwakeFromNib ()
        {
            base.AwakeFromNib ();
        }

        public new MainWindow Window {
            get { return (MainWindow)base.Window; }
        }
    }
}

Omówimy kluczowe elementy tej modyfikacji.

Najpierw zdefiniujemy nowe wystąpienie MainWindow klasy i przypiszemy je do właściwości podstawowego kontrolera Window okna:

CGRect contentRect = new CGRect (0, 0, 1000, 500);
base.Window = new MainWindow(contentRect, (NSWindowStyle.Titled | NSWindowStyle.Closable | NSWindowStyle.Miniaturizable | NSWindowStyle.Resizable), NSBackingStore.Buffered, false);

Definiujemy lokalizację okna ekranu z elementem CGRect. Podobnie jak układ współrzędnych okna, ekran definiuje (0,0) jako dolny lewy róg. Następnie zdefiniujemy styl okna przy użyciu operatora Or , aby połączyć co najmniej NSWindowStyle dwie funkcje:

... (NSWindowStyle.Titled | NSWindowStyle.Closable | NSWindowStyle.Miniaturizable | NSWindowStyle.Resizable) ...

Dostępne są następujące NSWindowStyle funkcje:

  • Obramowanie — okno nie będzie miało obramowania.
  • Tytuł — okno będzie mieć pasek tytułu.
  • Closable — okno ma przycisk Zamknij i można je zamknąć.
  • Miniaturyzacja — okno ma miniaturyzowany przycisk i można je zminimalizować.
  • Możliwość zmiany rozmiaru — okno będzie miało przycisk zmiany rozmiaru i można go zmienić.
  • Narzędzie — okno jest oknem stylu narzędzia (panel).
  • DocModal — jeśli okno jest panelem, będzie to modalne zamiast systemowe.
  • NonactivatingPanel — jeśli okno jest panelem, nie zostanie wykonane główne okno.
  • TexturedBackground — okno będzie miało teksturowane tło.
  • Nieskalowane — okno nie zostanie skalowane.
  • UnifiedTitleAndToolbar — obszary tytułu i paska narzędzi okna zostaną dołączone.
  • Hud — okno będzie wyświetlane jako panel ekranu z głową.
  • FullScreenWindow — okno może wprowadzać tryb pełnoekranowy.
  • FullSizeContentView — widok zawartości okna znajduje się za tytułem i obszarem paska narzędzi.

Dwie ostatnie właściwości definiują typ buforowania dla okna i jeśli rysunek okna zostanie odroczony. Aby uzyskać więcej informacji na NSWindowstemat programu , zobacz dokumentację dotyczącą wprowadzenia firmy Apple do systemu Windows .

Na koniec, ponieważ okno nie jest zawyżone z pliku .storyboard lub xib, musimy zasymulować go w naszym MainWindowController.cs przez wywołanie metody windows AwakeFromNib :

Window.AwakeFromNib ();

Umożliwi to kod w oknie tak samo jak standardowe okno załadowane z pliku .storyboard lub .xib.

Wyświetlanie okna

Po usunięciu pliku .storyboard lub .xib oraz MainWindow.cs i MainWindowController.cs zmodyfikowanych plików będziesz używać okna tak samo jak w przypadku dowolnego normalnego okna utworzonego w narzędziu Xcode Interface Builder z plikiem xib.

Poniższe polecenie utworzy nowe wystąpienie okna i jego kontrolera i wyświetli okno na ekranie:

private MainWindowController mainWindowController;
...

mainWindowController = new MainWindowController ();
mainWindowController.Window.MakeKeyAndOrderFront (this);

Na tym etapie, jeśli aplikacja zostanie uruchomiona, a przycisk kliknął kilka razy, zostaną wyświetlone następujące elementy:

Uruchamianie przykładowej aplikacji

Dodawanie okna tylko kodu

Jeśli chcemy dodać tylko kod, okno xibless do istniejącej aplikacji Xamarin.Mac kliknij prawym przyciskiem myszy projekt w okienku rozwiązania i wybierz polecenie Dodaj>nowy plik... W oknie dialogowym Nowy plik wybierz okno Xamarin.Mac>Cocoa z kontrolerem, jak pokazano poniżej:

Dodawanie nowego kontrolera okna

Podobnie jak wcześniej usuniemy domyślny plik storyboard lub xib z projektu (w tym przypadku SecondWindow.xib) i wykonaj kroki opisane w sekcji Przełączanie okna do użycia kodu powyżej, aby zastosować definicję okna do kodu.

Dodawanie elementu interfejsu użytkownika do okna w kodzie

Niezależnie od tego, czy okno zostało utworzone w kodzie, czy załadowane z pliku .storyboard lub xib, czasami chcemy dodać element interfejsu użytkownika do okna z kodu. Na przykład:

var ClickMeButton = new NSButton (new CGRect (10, 10, 100, 30)){
    AutoresizingMask = NSViewResizingMask.MinYMargin
};
MyWindow.ContentView.AddSubview (ClickMeButton);

Powyższy kod tworzy nowy NSButton i dodaje go do wystąpienia okna na potrzeby wyświetlania MyWindow . Zasadniczo każdy element interfejsu użytkownika, który można zdefiniować w narzędziu Interface Builder programu Xcode w pliku .storyboard lub xib, można utworzyć w kodzie i wyświetlić w oknie.

Definiowanie paska menu w kodzie

Z powodu bieżących ograniczeń na platformie Xamarin.Mac nie zaleca się tworzenia paska menu aplikacji Xamarin.Mac—NSMenuBar w kodzie, ale nadal używasz pliku Main.storyboard lub MainMenu.xib , aby go zdefiniować. Oznacza to, że można dodawać i usuwać menu i elementy menu w kodzie języka C#.

Na przykład zmodyfikuj plik AppDelegate.cs i utwórz metodę DidFinishLaunching podobną do następującej:

public override void DidFinishLaunching (NSNotification notification)
{
    mainWindowController = new MainWindowController ();
    mainWindowController.Window.MakeKeyAndOrderFront (this);

    // Create a Status Bar Menu
    NSStatusBar statusBar = NSStatusBar.SystemStatusBar;

    var item = statusBar.CreateStatusItem (NSStatusItemLength.Variable);
    item.Title = "Phrases";
    item.HighlightMode = true;
    item.Menu = new NSMenu ("Phrases");

    var address = new NSMenuItem ("Address");
    address.Activated += (sender, e) => {
        Console.WriteLine("Address Selected");
    };
    item.Menu.AddItem (address);

    var date = new NSMenuItem ("Date");
    date.Activated += (sender, e) => {
        Console.WriteLine("Date Selected");
    };
    item.Menu.AddItem (date);

    var greeting = new NSMenuItem ("Greeting");
    greeting.Activated += (sender, e) => {
        Console.WriteLine("Greetings Selected");
    };
    item.Menu.AddItem (greeting);

    var signature = new NSMenuItem ("Signature");
    signature.Activated += (sender, e) => {
        Console.WriteLine("Signature Selected");
    };
    item.Menu.AddItem (signature);
}

Powyższe polecenie tworzy menu Pasek stanu na podstawie kodu i wyświetla je po uruchomieniu aplikacji. Aby uzyskać więcej informacji na temat pracy z menu, zobacz dokumentację menu .

Podsumowanie

W tym artykule szczegółowo opatrzono tworzenie interfejsu użytkownika aplikacji Xamarin.Mac w kodzie języka C#, a nie przy użyciu narzędzia Interface Builder środowiska Xcode z plikami .storyboard lub .xib.