Kopieren und Einfügen in Xamarin.Mac

In diesem Artikel wird die Arbeit mit dem Pasteboard behandelt, um Kopieren und Einfügen in eine Xamarin.Mac-Anwendung bereitzustellen. Es zeigt, wie Sie mit Standarddatentypen arbeiten, die zwischen mehreren Apps gemeinsam genutzt werden können und wie benutzerdefinierte Daten in einer bestimmten App unterstützt werden können.

Überblick

Wenn Sie mit C# und .NET in einer Xamarin.Mac-Anwendung arbeiten, haben Sie Zugriff auf das gleiche Einfügen (Kopieren und Einfügen), die ein Entwickler hat Objective-C .

In diesem Artikel werden wir die beiden wichtigsten Möglichkeiten zur Verwendung des Pasteboards in einer Xamarin.Mac-App behandeln:

  1. Standarddatentypen – Da Einfügevorgänge in der Regel zwischen zwei nicht verbundenen Apps durchgeführt werden, kennt weder die App die Datentypen, die die andere unterstützt. Um das Potenzial für die Freigabe zu maximieren, kann das Pasteboard mehrere Darstellungen eines bestimmten Elements (mit einem Standardsatz gemeinsamer Datentypen) halten, damit die nutzungsintensive App die für ihre Anforderungen am besten geeignete Version auswählen kann.
  2. Benutzerdefinierte Daten – Um das Kopieren und Einfügen komplexer Daten in Ihrem Xamarin.Mac zu unterstützen, können Sie einen benutzerdefinierten Datentyp definieren, der vom Einfügenboard behandelt wird. Eine Vektorzeichnungs-App, mit der der Benutzer komplexe Shapes kopieren und einfügen kann, die aus mehreren Datentypen und Punkten bestehen.

Example of the running app

In diesem Artikel werden die Grundlagen der Arbeit mit dem Pasteboard in einer Xamarin.Mac-Anwendung behandelt, um Kopieren- und Einfügenvorgänge zu unterstützen. Es wird dringend vorgeschlagen, dass Sie zuerst den Artikel "Hello" und "Mac" durchlaufen, insbesondere die Einführung in Xcode- und Interface-Generator- undAktionsabschnitte , da sie wichtige Konzepte und Techniken behandelt, die wir in diesem Artikel verwenden werden.

Möglicherweise möchten Sie sich die C#-Klassen /Methoden zum Abschnitt "Xamarin.Mac Internals" ansehen, und sie erläutert die und attribute, die verwendet werden, um Objective-CIhre C#-Klassen an Objective-C Objekte und UI-Elemente zu verkabeln.RegisterExport

Erste Schritte mit dem Einfügen

Das Pasteboard stellt einen standardisierten Mechanismus zum Austausch von Daten innerhalb einer bestimmten Anwendung oder zwischen Anwendungen dar. Die typische Verwendung für ein Pasteboard in einer Xamarin.Mac-Anwendung besteht darin, Kopieren- und Einfügenvorgänge zu behandeln, aber auch eine Reihe anderer Vorgänge wird unterstützt (z & . B. Drag Drop and Application Services).

Um Sie schnell auf den Boden zu bringen, beginnen wir mit einer einfachen, praktischen Einführung in die Verwendung von Pasteboards in einer Xamarin.Mac-App. Später stellen wir eine ausführliche Erläuterung zur Funktionsweise des Pasteboards und der verwendeten Methoden bereit.

In diesem Beispiel erstellen wir eine einfache dokumentbasierte Anwendung, die ein Fenster verwaltet, das eine Bildansicht enthält. Der Benutzer kann Bilder zwischen Dokumenten in der App und aus anderen Apps oder mehreren Fenstern in derselben App kopieren und einfügen.

Erstellen des Xamarin-Projekts

Zunächst erstellen wir eine neue dokumentbasierte Xamarin.Mac-App, die wir kopieren und einfügen werden.

Gehen Sie folgendermaßen vor:

  1. Starten Sie Visual Studio für Mac, und klicken Sie auf den Link "Neue Project...".

  2. Wählen Sie MacAppCocoa-App>> aus, und klicken Sie dann auf die Schaltfläche "Weiter":

    Creating a new Cocoa app project

  3. Geben Sie für den Project Namen ein, und behalten Sie MacCopyPaste alles andere als Standard. Klicken Sie auf „Weiter:

    Setting the name of the project

  4. Klicken Sie auf die Schaltfläche "Erstellen ":

    Confirming the new project settings

Hinzufügen eines NSDocument

Als Nächstes fügen wir benutzerdefinierte NSDocument Klasse hinzu, die als Hintergrundspeicher für die Benutzeroberfläche der Anwendung fungiert. Es enthält eine einzelne Bildansicht und weiß, wie Sie ein Bild aus der Ansicht in das Standard-Einfügenboard kopieren und ein Bild aus dem Standard-Pasteboard aufnehmen und es in der Bildansicht anzeigen.

Klicken Sie mit der rechten Maustaste auf das Xamarin.Mac-Projekt im Lösungspad, und wählen Sie "Datei hinzufügen>".:

Adding an NSDocument to the project

Geben Sie für den NamenImageDocument ein, und klicken Sie auf Neu. Bearbeiten Sie die ImageDocument.cs-Klasse , und machen Sie es wie folgt aussehen:

using System;
using AppKit;
using Foundation;
using ObjCRuntime;

namespace MacCopyPaste
{
    [Register("ImageDocument")]
    public class ImageDocument : NSDocument
    {
        #region Computed Properties
        public NSImageView ImageView {get; set;}

        public ImageInfo Info { get; set; } = new ImageInfo();

        public bool ImageAvailableOnPasteboard {
            get {
                // Initialize the pasteboard
                NSPasteboard pasteboard = NSPasteboard.GeneralPasteboard;
                Class [] classArray  = { new Class ("NSImage") };

                // Check to see if an image is on the pasteboard
                return pasteboard.CanReadObjectForClasses (classArray, null);
            }
        }
        #endregion

        #region Constructor
        public ImageDocument ()
        {
        }
        #endregion

        #region Public Methods
        [Export("CopyImage:")]
        public void CopyImage(NSObject sender) {

            // Grab the current image
            var image = ImageView.Image;

            // Anything to process?
            if (image != null) {
                // Get the standard pasteboard
                var pasteboard = NSPasteboard.GeneralPasteboard;

                // Empty the current contents
                pasteboard.ClearContents();

                // Add the current image to the pasteboard
                pasteboard.WriteObjects (new NSImage[] {image});

                // Save the custom data class to the pastebaord
                pasteboard.WriteObjects (new ImageInfo[] { Info });

                // Using a Pasteboard Item
                NSPasteboardItem item = new NSPasteboardItem();
                string[] writableTypes = {"public.text"};

                // Add a data provier to the item
                ImageInfoDataProvider dataProvider = new ImageInfoDataProvider (Info.Name, Info.ImageType);
                var ok = item.SetDataProviderForTypes (dataProvider, writableTypes);

                // Save to pasteboard
                if (ok) {
                    pasteboard.WriteObjects (new NSPasteboardItem[] { item });
                }
            }

        }

        [Export("PasteImage:")]
        public void PasteImage(NSObject sender) {

            // Initialize the pasteboard
            NSPasteboard pasteboard = NSPasteboard.GeneralPasteboard;
            Class [] classArray  = { new Class ("NSImage") };

            bool ok = pasteboard.CanReadObjectForClasses (classArray, null);
            if (ok) {
                // Read the image off of the pasteboard
                NSObject [] objectsToPaste = pasteboard.ReadObjectsForClasses (classArray, null);
                NSImage image = (NSImage)objectsToPaste[0];

                // Display the new image
                ImageView.Image = image;
            }

            Class [] classArray2 = { new Class ("ImageInfo") };
            ok = pasteboard.CanReadObjectForClasses (classArray2, null);
            if (ok) {
                // Read the image off of the pasteboard
                NSObject [] objectsToPaste = pasteboard.ReadObjectsForClasses (classArray2, null);
                ImageInfo info = (ImageInfo)objectsToPaste[0];

            }

        }
        #endregion
    }
}

Sehen wir uns einige der folgenden Codedetails an.

Der folgende Code stellt eine Eigenschaft bereit, um zu testen, ob Bilddaten im Standard-Pasteboard vorhanden sind, wenn ein Bild verfügbar ist, true anders falsezurückgegeben wird:

public bool ImageAvailableOnPasteboard {
    get {
        // Initialize the pasteboard
        NSPasteboard pasteboard = NSPasteboard.GeneralPasteboard;
        Class [] classArray  = { new Class ("NSImage") };

        // Check to see if an image is on the pasteboard
        return pasteboard.CanReadObjectForClasses (classArray, null);
    }
}

Der folgende Code kopiert ein Bild aus der angefügten Bildansicht in das Standard-Pasteboard:

[Export("CopyImage:")]
public void CopyImage(NSObject sender) {

    // Grab the current image
    var image = ImageView.Image;

    // Anything to process?
    if (image != null) {
        // Get the standard pasteboard
        var pasteboard = NSPasteboard.GeneralPasteboard;

        // Empty the current contents
        pasteboard.ClearContents();

        // Add the current image to the pasteboard
        pasteboard.WriteObjects (new NSImage[] {image});

        // Save the custom data class to the pastebaord
        pasteboard.WriteObjects (new ImageInfo[] { Info });

        // Using a Pasteboard Item
        NSPasteboardItem item = new NSPasteboardItem();
        string[] writableTypes = {"public.text"};

        // Add a data provider to the item
        ImageInfoDataProvider dataProvider = new ImageInfoDataProvider (Info.Name, Info.ImageType);
        var ok = item.SetDataProviderForTypes (dataProvider, writableTypes);

        // Save to pasteboard
        if (ok) {
            pasteboard.WriteObjects (new NSPasteboardItem[] { item });
        }
    }

}

Und der folgende Code fügt ein Bild aus dem Standard-Pasteboard ein und zeigt es in der angefügten Bildansicht an (wenn das Einfügenboard ein gültiges Bild enthält):

[Export("PasteImage:")]
public void PasteImage(NSObject sender) {

    // Initialize the pasteboard
    NSPasteboard pasteboard = NSPasteboard.GeneralPasteboard;
    Class [] classArray  = { new Class ("NSImage") };

    bool ok = pasteboard.CanReadObjectForClasses (classArray, null);
    if (ok) {
        // Read the image off of the pasteboard
        NSObject [] objectsToPaste = pasteboard.ReadObjectsForClasses (classArray, null);
        NSImage image = (NSImage)objectsToPaste[0];

        // Display the new image
        ImageView.Image = image;
    }

    Class [] classArray2 = { new Class ("ImageInfo") };
    ok = pasteboard.CanReadObjectForClasses (classArray2, null);
    if (ok) {
        // Read the image off of the pasteboard
        NSObject [] objectsToPaste = pasteboard.ReadObjectsForClasses (classArray2, null);
        ImageInfo info = (ImageInfo)objectsToPaste[0]
    }
}

Mit diesem Dokument erstellen wir die Benutzeroberfläche für die Xamarin.Mac-App.

Erstellen der Benutzeroberfläche

Doppelklicken Sie auf die Datei "Main.storyboard ", um sie in Xcode zu öffnen. Fügen Sie als Nächstes eine Symbolleiste und ein Bild gut hinzu und konfigurieren Sie sie wie folgt:

Editing the toolbar

Fügen Sie dem Symbolleistenelement "Bildsymbolleiste " eine Kopie hinzu und fügen Sie sie zur linken Seite der Symbolleiste hinzu. Wir verwenden diese als Verknüpfungen zum Kopieren und Einfügen im Menü "Bearbeiten". Fügen Sie als Nächstes vier Bildsymbolleistenelemente zur rechten Seite der Symbolleiste hinzu. Wir verwenden diese, um das Bild gut mit einigen Standardbildern aufzufüllen.

Weitere Informationen zur Arbeit mit Symbolleisten finden Sie in unserer Symbolleistendokumentation .

Als Nächstes zeigen wir die folgenden Verkaufsstellen und Aktionen für unsere Symbolleistenelemente und das Bild gut an:

Creating outlets and actions

Weitere Informationen zur Arbeit mit Verkaufsstellen und Aktionen finden Sie im Abschnitt "Outlets und Aktionen" unserer Dokumentation "Hello, Mac ".

Aktivieren der Benutzeroberfläche

Mit unserer benutzeroberfläche, die in Xcode und unserem UI-Element über Verkaufsstellen und Aktionen verfügbar gemacht wurde, müssen wir den Code hinzufügen, um die Benutzeroberfläche zu aktivieren. Doppelklicken Sie auf die Datei "ImageWindow.cs " im Lösungspad , und machen Sie es wie folgt aussehen:

using System;
using Foundation;
using AppKit;

namespace MacCopyPaste
{
    public partial class ImageWindow : NSWindow
    {
        #region Private Variables
        ImageDocument document;
        #endregion

        #region Computed Properties
        [Export ("Document")]
        public ImageDocument Document {
            get {
                return document;
            }
            set {
                WillChangeValue ("Document");
                document = value;
                DidChangeValue ("Document");
            }
        }

        public ViewController ImageViewController {
            get { return ContentViewController as ViewController; }
        }

        public NSImage Image {
            get {
                return ImageViewController.Image;
            }
            set {
                ImageViewController.Image = value;
            }
        }
        #endregion

        #region Constructor
        public ImageWindow (IntPtr handle) : base (handle)
        {
        }
        #endregion

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

            // Create a new document instance
            Document = new ImageDocument ();

            // Attach to image view
            Document.ImageView = ImageViewController.ContentView;
        }
        #endregion

        #region Public Methods
        public void CopyImage (NSObject sender)
        {
            Document.CopyImage (sender);
        }

        public void PasteImage (NSObject sender)
        {
            Document.PasteImage (sender);
        }

        public void ImageOne (NSObject sender)
        {
            // Load image
            Image = NSImage.ImageNamed ("Image01.jpg");

            // Set image info
            Document.Info.Name = "city";
            Document.Info.ImageType = "jpg";
        }

        public void ImageTwo (NSObject sender)
        {
            // Load image
            Image = NSImage.ImageNamed ("Image02.jpg");

            // Set image info
            Document.Info.Name = "theater";
            Document.Info.ImageType = "jpg";
        }

        public void ImageThree (NSObject sender)
        {
            // Load image
            Image = NSImage.ImageNamed ("Image03.jpg");

            // Set image info
            Document.Info.Name = "keyboard";
            Document.Info.ImageType = "jpg";
        }

        public void ImageFour (NSObject sender)
        {
            // Load image
            Image = NSImage.ImageNamed ("Image04.jpg");

            // Set image info
            Document.Info.Name = "trees";
            Document.Info.ImageType = "jpg";
        }
        #endregion
    }
}

Sehen wir uns diesen Code im Detail unten an.

Zunächst stellen wir eine Instanz der Klasse zur Verfügung, die ImageDocument wir oben erstellt haben:

private ImageDocument _document;
...

[Export ("Document")]
public ImageDocument Document {
    get { return _document; }
    set {
        WillChangeValue ("Document");
        _document = value;
        DidChangeValue ("Document");
    }
}

ExportMithilfe von , WillChangeValue und DidChangeValue, haben wir die Document Eigenschaft eingerichtet, um Key-Value Codieren und Datenbindung in Xcode zu ermöglichen.

Wir stellen auch das Bild aus dem Bild bereit, das wir unserer Benutzeroberfläche in Xcode mit der folgenden Eigenschaft hinzugefügt haben:

public ViewController ImageViewController {
    get { return ContentViewController as ViewController; }
}

public NSImage Image {
    get {
        return ImageViewController.Image;
    }
    set {
        ImageViewController.Image = value;
    }
}

Wenn das Hauptfenster geladen und angezeigt wird, erstellen wir eine Instanz unserer ImageDocument Klasse und fügen das Bild der Benutzeroberfläche gut mit dem folgenden Code an:

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

    // Create a new document instance
    Document = new ImageDocument ();

    // Attach to image view
    Document.ImageView = ImageViewController.ContentView;
}

Als Reaktion auf den Benutzer, der auf die Symbolleistenelemente kopieren und einfügen klickt, rufen wir die Instanz der ImageDocument Klasse auf, um die tatsächliche Arbeit zu erledigen:

partial void CopyImage (NSObject sender) {
    Document.CopyImage(sender);
}

partial void PasteImage (Foundation.NSObject sender) {
    Document.PasteImage(sender);
}

Aktivieren der Menüs "Datei" und "Bearbeiten"

Das letzte, was wir tun müssen, ist die Aktivierung des Neuen Menüelements im Menü "Datei " (zum Erstellen neuer Instanzen unseres Hauptfensters) und zum Aktivieren des Ausschneidens, Kopieren und Einfügen von Menüelementen im Menü "Bearbeiten ".

Zum Aktivieren des Neuen Menüelements bearbeiten Sie die Datei "AppDelegate.cs ", und fügen Sie den folgenden Code hinzu:

public int UntitledWindowCount { get; set;} =1;
...

[Export ("newDocument:")]
void NewDocument (NSObject sender) {
    // Get new window
    var storyboard = NSStoryboard.FromName ("Main", null);
    var controller = storyboard.InstantiateControllerWithIdentifier ("MainWindow") as NSWindowController;

    // Display
    controller.ShowWindow(this);

    // Set the title
    controller.Window.Title = (++UntitledWindowCount == 1) ? "untitled" : string.Format ("untitled {0}", UntitledWindowCount);
}

Weitere Informationen finden Sie im Abschnitt "Arbeiten mit mehreren Windows" unserer Windows Dokumentation.

Um die Menüelemente ausschneiden, kopierenund einfügen zu aktivieren, bearbeiten Sie die Datei "AppDelegate.cs ", und fügen Sie den folgenden Code hinzu:

[Export("copy:")]
void CopyImage (NSObject sender)
{
    // Get the main window
    var window = NSApplication.SharedApplication.KeyWindow as ImageWindow;

    // Anything to do?
    if (window == null)
        return;

    // Copy the image to the clipboard
    window.Document.CopyImage (sender);
}

[Export("cut:")]
void CutImage (NSObject sender)
{
    // Get the main window
    var window = NSApplication.SharedApplication.KeyWindow as ImageWindow;

    // Anything to do?
    if (window == null)
        return;

    // Copy the image to the clipboard
    window.Document.CopyImage (sender);

    // Clear the existing image
    window.Image = null;
}

[Export("paste:")]
void PasteImage (NSObject sender)
{
    // Get the main window
    var window = NSApplication.SharedApplication.KeyWindow as ImageWindow;

    // Anything to do?
    if (window == null)
        return;

    // Paste the image from the clipboard
    window.Document.PasteImage (sender);
}

Für jedes Menüelement erhalten wir das aktuelle, oberste, Schlüsselfenster und casten sie in unsere ImageWindow Klasse:

var window = NSApplication.SharedApplication.KeyWindow as ImageWindow;

Von dort rufen wir die ImageDocument Klasseninstanz dieses Fensters auf, um die Aktionen zum Kopieren und Einfügen zu behandeln. Beispiel:

window.Document.CopyImage (sender);

Es werden nur Menüelemente ausschneiden, kopierenund einfügen angezeigt, wenn Bilddaten im Standard-Einfügen oder in der Bildbeschriftung des aktuellen aktiven Fensters vorhanden sind.

Fügen wir der Xamarin.Mac-Projekt eine Datei "EditMenuDelegate.cs " hinzu, und machen Sie es wie folgt aussehen:

using System;
using AppKit;

namespace MacCopyPaste
{
    public class EditMenuDelegate : NSMenuDelegate
    {
        #region Override Methods
        public override void MenuWillHighlightItem (NSMenu menu, NSMenuItem item)
        {
        }

        public override void NeedsUpdate (NSMenu menu)
        {
            // Get list of menu items
            NSMenuItem[] Items = menu.ItemArray ();

            // Get the key window and determine if the required images are available
            var window = NSApplication.SharedApplication.KeyWindow as ImageWindow;
            var hasImage = (window != null) && (window.Image != null);
            var hasImageOnPasteboard = (window != null) && window.Document.ImageAvailableOnPasteboard;

            // Process every item in the menu
            foreach(NSMenuItem item in Items) {
                // Take action based on the menu title
                switch (item.Title) {
                case "Cut":
                case "Copy":
                case "Delete":
                    // Only enable if there is an image in the view
                    item.Enabled = hasImage;
                    break;
                case "Paste":
                    // Only enable if there is an image on the pasteboard
                    item.Enabled = hasImageOnPasteboard;
                    break;
                default:
                    // Only enable the item if it has a sub menu
                    item.Enabled = item.HasSubmenu;
                    break;
                }
            }
        }
        #endregion
    }
}

Erneut erhalten wir das aktuelle, oberste Fenster und verwenden seine ImageDocument Klasseninstanz, um zu sehen, ob die erforderlichen Bilddaten vorhanden sind. Anschließend verwenden wir die MenuWillHighlightItem Methode, um jedes Element basierend auf diesem Zustand zu aktivieren oder zu deaktivieren.

Bearbeiten Sie die Datei "AppDelegate.cs ", und machen Sie die DidFinishLaunching Methode wie folgt aussehen:

public override void DidFinishLaunching (NSNotification notification)
{
    // Disable automatic item enabling on the Edit menu
    EditMenu.AutoEnablesItems = false;
    EditMenu.Delegate = new EditMenuDelegate ();
}

Zunächst deaktivieren wir die automatische Aktivierung und Deaktivierung von Menüelementen im Menü "Bearbeiten". Als Nächstes fügen wir eine Instanz der klasse an, die EditMenuDelegate wir oben erstellt haben.

Weitere Informationen finden Sie in der Dokumentation zu Menüs .

Testen der App

Mit allem, was vorhanden ist, sind wir bereit, die Anwendung zu testen. Erstellen und Ausführen der App und die Hauptschnittstelle wird angezeigt:

Running the application

Wenn Sie das Menü "Bearbeiten" öffnen, beachten Sie, dass "Ausschneiden","Kopieren" und "Einfügen" deaktiviert sind, da es kein Bild im Bild oder im Standard-Einfügen gibt:

Opening the Edit menu

Wenn Sie dem Bild ein Bild gut hinzufügen und das Menü "Bearbeiten" erneut öffnen, werden die Elemente jetzt aktiviert:

Showing the Edit menu items are enabled

Wenn Sie das Bild kopieren und im Menü " Neu " auswählen, können Sie dieses Bild in das neue Fenster einfügen:

Pasting an image into a new window

In den folgenden Abschnitten sehen wir uns die Arbeit mit dem Pasteboard in einer Xamarin.Mac-Anwendung ausführlich an.

Informationen zum Einfügen

In macOS (früher als OS X bezeichnet) bietet das Pasteboard (NSPasteboard) Unterstützung für mehrere Serverprozesse wie Kopieren & , & Ziehen Drop und Application Services. In den folgenden Abschnitten werden wir einen näheren Blick auf verschiedene Schlüsselpastaturkonzepte nehmen.

Was ist ein Pasteboard?

Die NSPasteboard Klasse bietet einen standardisierten Mechanismus zum Austausch von Informationen zwischen Anwendungen oder innerhalb einer bestimmten App. Die Hauptfunktion eines Pasteboards dient zum Behandeln von Kopier- und Einfügevorgängen:

  1. Wenn der Benutzer ein Element in einer App auswählt und das Menüelement "Ausschneiden " oder " Kopieren " verwendet, werden mindestens eine Darstellung des ausgewählten Elements auf dem Einfügen platziert.
  2. Wenn der Benutzer das Menüelement " Einfügen " (innerhalb derselben App oder einer anderen App) verwendet, wird die Version der Daten, die er verarbeiten kann, aus dem Pasteboard kopiert und der App hinzugefügt.

Weniger offensichtliche Einfügeelemente umfassen Such-, Ziehen-, Ziehen- und Drop- und Anwendungsdienstevorgänge:

  • Wenn der Benutzer einen Drag-Vorgang initiiert, wird die Ziehendaten in das Pasteboard kopiert. Wenn der Ziehenvorgang mit einem Drop auf eine andere App endet, kopiert diese App die Daten aus dem Einfügen.
  • Für Übersetzungsdienste wird die zu übersetzenden Daten durch die anfordernde App in das Einfügeboard kopiert. Der Anwendungsdienst ruft die Daten aus dem Einfügen ab, führt die Übersetzung aus, fügt dann die Daten wieder in das Pasteboard ein.

In ihrer einfachsten Form werden Pasteboards verwendet, um Daten innerhalb einer bestimmten App oder zwischen Apps zu verschieben und dort in einem speziellen globalen Speicherbereich außerhalb des App-Prozesses vorhanden. Während die Konzepte der Pasteboards leicht zu erfassen sind, gibt es mehrere komplexere Details, die berücksichtigt werden müssen. Dies wird unten ausführlich behandelt.

Benannte Pasteboards

Ein Pasteboard kann öffentlich oder privat sein und kann für eine Vielzahl von Zwecken innerhalb einer Anwendung oder zwischen mehreren Apps verwendet werden. macOS bietet mehrere Standard-Pasteboards, die jeweils eine bestimmte, gut definierte Verwendung enthalten:

  • NSGeneralPboard - Das Standard-Pasteboard für Ausschneiden, Kopieren und Einfügen von Vorgängen.
  • NSRulerPboard - Unterstützt Ausschneiden, Kopieren und Einfügen von Vorgängen in Linealen.
  • NSFontPboard - Unterstützt Ausschneiden, Kopieren und Einfügen von Vorgängen auf NSFont Objekten.
  • NSFindPboard - Unterstützt anwendungsspezifische Suchbereiche, die Suchtext freigeben können.
  • NSDragPboard - Unterstützt Drag & Drop-Vorgänge .

Für die meisten Situationen verwenden Sie eine der system definierten Pasteboards. Es kann jedoch Situationen geben, in denen Sie eigene Pasteboards erstellen müssen. In diesen Situationen können Sie die FromName (string name) Methode der NSPasteboard Klasse verwenden, um ein benutzerdefiniertes Pasteboard mit dem Angegebenen Namen zu erstellen.

Optional können Sie die CreateWithUniqueName Methode der NSPasteboard Klasse aufrufen, um ein eindeutig benanntes Pasteboard zu erstellen.

Einfügen von Elementen

Jede Datenmenge, die eine Anwendung in ein Pasteboard schreibt, wird als Einfügeelement angesehen, und ein Einfügeboard kann mehrere Elemente gleichzeitig halten. Auf diese Weise kann eine App mehrere Versionen der Daten schreiben, die in ein Einfügeboard kopiert werden (z. B. nur Text und formatierter Text), und die abgerufene App kann nur die Daten lesen, die sie verarbeiten kann (z. B. nur nur den nur Text).

Datendarstellungen und einheitliche Typbezeichner

Einfügevorgänge werden in der Regel zwischen zwei (oder mehr) Anwendungen durchgeführt, die keine Kenntnisse übereinander oder die Typen von Daten haben, die jeder behandeln kann. Wie im obigen Abschnitt angegeben, kann ein Pasteboard mehrere Darstellungen der Daten enthalten, die kopiert und eingefügt werden.

Jede Darstellung wird über einen Uniform Type Identifier (UTI) identifiziert, der nichts mehr als eine einfache Zeichenfolge ist, die den Typ des angezeigten Datums eindeutig identifiziert (weitere Informationen finden Sie in der Dokumentation zur Übersicht über die Einheitliche Typbezeichner von Apple).

Wenn Sie einen benutzerdefinierten Datentyp erstellen (z. B. ein Zeichnungsobjekt in einer Vektorzeichnungs-App), können Sie eigene UTI erstellen, um sie eindeutig in Kopieren- und Einfügen-Vorgängen zu identifizieren.

Wenn eine App auf das Einfügen von Daten vorbereitet, die aus einem Pasteboard kopiert wurden, muss sie die Darstellung finden, die am besten zu ihren Fähigkeiten passt (falls vorhanden). Normalerweise ist dies der reichste Typ, der verfügbar ist (z. B. formatierter Text für eine Textverarbeitungs-App), zurück auf die einfachsten Formulare zurück, die als erforderlich verfügbar sind (Nur-Text für einen einfachen Text-Editor).

Zugesagte Daten

Im Allgemeinen sollten Sie so viele Darstellungen der Daten bereitstellen, die wie möglich kopiert werden, um die Freigabe zwischen Apps zu maximieren. Aufgrund von Zeit- oder Speichereinschränkungen kann es jedoch unpraktisch sein, jeden Datentyp tatsächlich in das Pasteboard zu schreiben.

In dieser Situation können Sie die erste Datendarstellung auf dem Pasteboard platzieren, und die empfangende App kann eine andere Darstellung anfordern, die direkt vor dem Einfügenvorgang generiert werden kann.

Wenn Sie das ursprüngliche Element in das Einfügenboard platzieren, geben Sie an, dass eine oder mehrere der verfügbaren Darstellungen von einem Objekt bereitgestellt werden, das der NSPasteboardItemDataProvider Schnittstelle entspricht. Diese Objekte stellen die zusätzlichen Darstellungen nach Bedarf bereit, wie von der empfangenden App angefordert.

Anzahl ändern

Jedes Pasteboard verwaltet eine Änderungsanzahl , die jedes Mal, wenn ein neuer Besitzer deklariert wird. Eine App kann bestimmen, ob sich der Inhalt des Einfügens seit dem letzten Mal geändert hat, indem der Wert der Änderungsanzahl überprüft wird.

Verwenden Sie die Methoden und ClearContents Methoden der NSPasteboard Klasse, um die ChangeCount Änderungsanzahl eines bestimmten Pasteboards zu ändern.

Kopieren von Daten in ein Einfügeboard

Sie führen einen Kopiervorgang aus, indem Sie zuerst auf ein Pasteboard zugreifen, alle vorhandenen Inhalte löschen und so viele Darstellungen der Daten schreiben, wie für das Einfügen erforderlich sind.

Beispiel:

// Get the standard pasteboard
var pasteboard = NSPasteboard.GeneralPasteboard;

// Empty the current contents
pasteboard.ClearContents();

// Add the current image to the pasteboard
pasteboard.WriteObjects (new NSImage[] {image});

Normalerweise schreiben Sie einfach an das allgemeine Einfügen, wie wir im obigen Beispiel ausgeführt haben. Jedes Objekt, das Sie an die Methode senden, muss der INSPasteboardWritingWriteObjects Schnittstelle entsprechen. Mehrere integrierte Klassen (zNSString. B. , NSColorNSAttributedStringNSImageNSURLund NSPasteboardItem) entsprechen dieser Schnittstelle automatisch.

Wenn Sie eine benutzerdefinierte Datenklasse in das Pasteboard schreiben, muss sie der INSPasteboardWriting Schnittstelle entsprechen oder in eine Instanz der NSPasteboardItem Klasse umgebrochen werden (siehe Abschnitt " Benutzerdefinierte Datentypen " unten).

Lesen von Daten aus einem Pasteboard

Wie oben erwähnt, können mehrere Darstellungen der kopierten Daten in das Pasteboard geschrieben werden, um das Potenzial für die Freigabe von Daten zwischen Apps zu maximieren. Es ist bis zur empfangenden App möglich, die höchste Version für ihre Funktionen auszuwählen (falls vorhanden).

Einfacher Einfügevorgang

Sie lesen Daten aus dem Pasteboard mithilfe der ReadObjectsForClasses Methode. Es erfordert zwei Parameter:

  1. Ein Array basierender NSObject Klassentypen, die Sie aus dem Pasteboard lesen möchten. Sie sollten dies zuerst mit dem gewünschten Datentyp bestellen, wobei alle verbleibenden Typen in der Verringerung der Einstellung vorhanden sind.
  2. Ein Wörterbuch mit zusätzlichen Einschränkungen (z. B. einschränken auf bestimmte URL-Inhaltstypen) oder ein leeres Wörterbuch, wenn keine weiteren Einschränkungen erforderlich sind.

Die Methode gibt ein Array von Elementen zurück, die die von uns übergebenen Kriterien erfüllen und daher die gleiche Anzahl von Datentypen enthalten, die angefordert werden. Es ist auch möglich, dass keine der angeforderten Typen vorhanden sind und ein leeres Array zurückgegeben wird.

Im folgenden Code wird beispielsweise überprüft, ob eine NSImage in der allgemeinen Einfügeseite vorhanden ist und in einem Bild gut angezeigt wird, wenn dies der Fall ist:

[Export("PasteImage:")]
public void PasteImage(NSObject sender) {

    // Initialize the pasteboard
    NSPasteboard pasteboard = NSPasteboard.GeneralPasteboard;
    Class [] classArray  = { new Class ("NSImage") };

    bool ok = pasteboard.CanReadObjectForClasses (classArray, null);
    if (ok) {
        // Read the image off of the pasteboard
        NSObject [] objectsToPaste = pasteboard.ReadObjectsForClasses (classArray, null);
        NSImage image = (NSImage)objectsToPaste[0];

        // Display the new image
        ImageView.Image = image;
    }

    Class [] classArray2 = { new Class ("ImageInfo") };
    ok = pasteboard.CanReadObjectForClasses (classArray2, null);
    if (ok) {
        // Read the image off of the pasteboard
        NSObject [] objectsToPaste = pasteboard.ReadObjectsForClasses (classArray2, null);
        ImageInfo info = (ImageInfo)objectsToPaste[0];
            }
}

Anfordern mehrerer Datentypen

Basierend auf dem Typ der erstellten Xamarin.Mac-Anwendung kann es mehrere Darstellungen der eingefügten Daten behandeln. In dieser Situation gibt es zwei Szenarien zum Abrufen von Daten aus dem Pasteboard:

  1. Rufen Sie eine einzelne Aufrufe der ReadObjectsForClasses Methode auf und geben Sie ein Array aller gewünschten Darstellungen (in der bevorzugten Reihenfolge) an.
  2. Führen Sie mehrere Aufrufe an die Methode aus, die ReadObjectsForClasses jedes Mal ein anderes Array von Typen fordert.

Weitere Informationen zum Abrufen von Daten aus einem Pasteboard finden Sie oben im Abschnitt " Einfaches Einfügen" .

Überprüfen auf vorhandene Datentypen

Es gibt Zeiten, in denen Sie überprüfen möchten, ob ein Pasteboard eine bestimmte Datendarstellung enthält, ohne tatsächlich die Daten aus dem Pasteboard zu lesen (z. B. das Aktivieren des Menüelements "Einfügen", nur wenn gültige Daten vorhanden sind).

Rufen Sie die CanReadObjectForClasses Methode des Pasteboards auf, um zu sehen, ob es einen bestimmten Typ enthält.

Der folgende Code bestimmt beispielsweise, ob das allgemeine Einfügen eine NSImage Instanz enthält:

public bool ImageAvailableOnPasteboard {
    get {
        // Initialize the pasteboard
        NSPasteboard pasteboard = NSPasteboard.GeneralPasteboard;
        Class [] classArray  = { new Class ("NSImage") };

        // Check to see if an image is on the pasteboard
        return pasteboard.CanReadObjectForClasses (classArray, null);
    }
}

Lese-URLs aus dem Einfügenboard

Basierend auf der Funktion einer bestimmten Xamarin.Mac-App kann es erforderlich sein, URLs aus einem Einfügen zu lesen, aber nur, wenn sie einen bestimmten Satz von Kriterien erfüllen (z. B. auf Dateien oder URLs eines bestimmten Datentyps). In dieser Situation können Sie zusätzliche Suchkriterien mithilfe des zweiten Parameters der CanReadObjectForClasses Methoden angeben ReadObjectsForClasses .

Benutzerdefinierte Datentypen

Es gibt Zeiten, in denen Sie Ihre eigenen benutzerdefinierten Typen aus einer Xamarin.Mac-App speichern müssen. So kann beispielsweise eine Vektorzeichnungs-App, mit der der Benutzer Zeichnungsobjekte kopieren und einfügen kann.

In dieser Situation müssen Sie Ihre benutzerdefinierte Datenklasse so entwerfen, dass sie von ihnen erbtNSObject, und sie entspricht einigen Schnittstellen (INSCodingINSPasteboardWritingund INSPasteboardReading). Optional können Sie eine NSPasteboardItem Kapselung der Daten verwenden, die kopiert oder eingefügt werden sollen.

Beide Optionen werden unten ausführlich behandelt.

Verwenden einer benutzerdefinierten Klasse

In diesem Abschnitt werden wir die einfache Beispiel-App erweitern, die wir am Anfang dieses Dokuments erstellt haben und eine benutzerdefinierte Klasse hinzufügen, um Informationen zu dem Bild nachzuverfolgen, das wir zwischen Fenstern kopieren und einfügen.

Fügen Sie dem Projekt eine neue Klasse hinzu, und rufen Sie es ImageInfo.cs auf. Bearbeiten Sie die Datei, und machen Sie es wie folgt aussehen:

using System;
using AppKit;
using Foundation;

namespace MacCopyPaste
{
    [Register("ImageInfo")]
    public class ImageInfo : NSObject, INSCoding, INSPasteboardWriting, INSPasteboardReading
    {
        #region Computed Properties
        [Export("name")]
        public string Name { get; set; }

        [Export("imageType")]
        public string ImageType { get; set; }
        #endregion

        #region Constructors
        [Export ("init")]
        public ImageInfo ()
        {
        }
        
        public ImageInfo (IntPtr p) : base (p)
        {
        }

        [Export ("initWithCoder:")]
        public ImageInfo(NSCoder decoder) {

            // Decode data
            NSString name = decoder.DecodeObject("name") as NSString;
            NSString type = decoder.DecodeObject("imageType") as NSString;

            // Save data
            Name = name.ToString();
            ImageType = type.ToString ();
        }
        #endregion

        #region Public Methods
        [Export ("encodeWithCoder:")]
        public void EncodeTo (NSCoder encoder) {

            // Encode data
            encoder.Encode(new NSString(Name),"name");
            encoder.Encode(new NSString(ImageType),"imageType");
        }

        [Export ("writableTypesForPasteboard:")]
        public virtual string[] GetWritableTypesForPasteboard (NSPasteboard pasteboard) {
            string[] writableTypes = {"com.xamarin.image-info", "public.text"};
            return writableTypes;
        }

        [Export ("pasteboardPropertyListForType:")]
        public virtual NSObject GetPasteboardPropertyListForType (string type) {

            // Take action based on the requested type
            switch (type) {
            case "com.xamarin.image-info":
                return NSKeyedArchiver.ArchivedDataWithRootObject(this);
            case "public.text":
                return new NSString(string.Format("{0}.{1}", Name, ImageType));
            }

            // Failure, return null
            return null;
        }

        [Export ("readableTypesForPasteboard:")]
        public static string[] GetReadableTypesForPasteboard (NSPasteboard pasteboard){
            string[] readableTypes = {"com.xamarin.image-info", "public.text"};
            return readableTypes;
        }

        [Export ("readingOptionsForType:pasteboard:")]
        public static NSPasteboardReadingOptions GetReadingOptionsForType (string type, NSPasteboard pasteboard) {

            // Take action based on the requested type
            switch (type) {
            case "com.xamarin.image-info":
                return NSPasteboardReadingOptions.AsKeyedArchive;
            case "public.text":
                return NSPasteboardReadingOptions.AsString;
            }

            // Default to property list
            return NSPasteboardReadingOptions.AsPropertyList;
        }

        [Export ("initWithPasteboardPropertyList:ofType:")]
        public NSObject InitWithPasteboardPropertyList (NSObject propertyList, string type) {

            // Take action based on the requested type
            switch (type) {
            case "com.xamarin.image-info":
                return new ImageInfo();
            case "public.text":
                return new ImageInfo();
            }

            // Failure, return null
            return null;
        }
        #endregion
    }
}
    

In den folgenden Abschnitten sehen wir uns diese Klasse ausführlich an.

Vererbung und Schnittstellen

Bevor eine benutzerdefinierte Datenklasse in ein Pasteboard geschrieben oder gelesen werden kann, muss sie den und den INSPastebaordWritingINSPasteboardReading Schnittstellen entsprechen. Darüber hinaus muss er von der INSCoding Schnittstelle erben NSObject und auch entsprechen:

[Register("ImageInfo")]
public class ImageInfo : NSObject, INSCoding, INSPasteboardWriting, INSPasteboardReading
...

Die Klasse muss auch für die Verwendung der Register Richtlinie verfügbar Objective-C gemacht werden, und sie muss alle erforderlichen Eigenschaften oder Methoden mithilfe Exportverfügbar machen. Beispiel:

[Export("name")]
public string Name { get; set; }

[Export("imageType")]
public string ImageType { get; set; }

Wir stellen die beiden Datenfelder dar, die diese Klasse enthält – den Namen des Bilds und seinen Typ (jpg, png usw.).

Weitere Informationen finden Sie im Abschnitt "Xamarin.Mac Internals"-Dokumentation über die Exposing C#-Klassen /MethodenObjective-C, die RegisterExport verwendet werden, um Ihre C#-Klassen an Objective-C Objekte und UI-Elemente zu verkabeln.

Konstruktoren

Zwei Konstruktoren (ordnungsgemäß verfügbar Objective-Cgemacht) sind für unsere benutzerdefinierte Datenklasse erforderlich, damit sie aus einem Pasteboard gelesen werden kann:

[Export ("init")]
public ImageInfo ()
{
}

[Export ("initWithCoder:")]
public ImageInfo(NSCoder decoder) {

    // Decode data
    NSString name = decoder.DecodeObject("name") as NSString;
    NSString type = decoder.DecodeObject("imageType") as NSString;

    // Save data
    Name = name.ToString();
    ImageType = type.ToString ();
}

Zunächst stellen wir den leeren Konstruktor unter der Standardmethode Objective-C von init.

Als Nächstes stellen wir einen kompatiblen Konstruktor zur Erstellung einer NSCoding neuen Instanz des Objekts aus dem Pasteboard zur Verfügung, wenn er unter dem exportierten Namen initWithCodereingefügt wird.

Dieser Konstruktor verwendet NSCoder eine (wie von einem NSKeyedArchiver beim Schreiben in das Pasteboard erstellte), extrahiert die Schlüssel-/Wert-paarten Daten und speichert sie in die Eigenschaftenfelder der Datenklasse.

Schreiben an das Einfügeboard

Durch die Übereinstimmung mit der Schnittstelle müssen wir zwei Methoden verfügbar machen und optional eine dritte Methode bereitstellen, sodass die Klasse in das INSPasteboardWriting Pasteboard geschrieben werden kann.

Zunächst müssen wir dem Einfügen mitteilen, in welche Datentypdarstellungen die benutzerdefinierte Klasse geschrieben werden kann:

[Export ("writableTypesForPasteboard:")]
public virtual string[] GetWritableTypesForPasteboard (NSPasteboard pasteboard) {
    string[] writableTypes = {"com.xamarin.image-info", "public.text"};
    return writableTypes;
}

Jede Darstellung wird über einen Uniform Type Identifier (UTI) identifiziert, der nichts mehr als eine einfache Zeichenfolge ist, die den Typ der angezeigten Daten eindeutig identifiziert (weitere Informationen finden Sie in der Dokumentation zur Übersicht über die Einheitliche Typbezeichner von Apple).

Für unser benutzerdefiniertes Format erstellen wir unsere eigene UTI: "com.xamarin.image-info" (beachten Sie, dass sich die umgekehrte Notation wie ein App-Bezeichner befindet). Unsere Klasse ist auch in der Lage, eine Standardzeichenfolge in das Pasteboard (public.text) zu schreiben.

Als Nächstes müssen wir das Objekt im angeforderten Format erstellen, das tatsächlich in das Pasteboard geschrieben wird:

[Export ("pasteboardPropertyListForType:")]
public virtual NSObject GetPasteboardPropertyListForType (string type) {

    // Take action based on the requested type
    switch (type) {
    case "com.xamarin.image-info":
        return NSKeyedArchiver.ArchivedDataWithRootObject(this);
    case "public.text":
        return new NSString(string.Format("{0}.{1}", Name, ImageType));
    }

    // Failure, return null
    return null;
}

Für den public.text Typ geben wir ein einfaches, formatiertes NSString Objekt zurück. Für den benutzerdefinierten Typ verwenden wir eine NSKeyedArchiver und die NSCoder Schnittstelle, um die benutzerdefinierte com.xamarin.image-info Datenklasse in ein schlüssel-/wertpaares Archiv zu codieren. Wir müssen die folgende Methode implementieren, um die Codierung tatsächlich zu behandeln:

[Export ("encodeWithCoder:")]
public void EncodeTo (NSCoder encoder) {

    // Encode data
    encoder.Encode(new NSString(Name),"name");
    encoder.Encode(new NSString(ImageType),"imageType");
}

Die einzelnen Schlüssel-/Wertpaare werden in den Encoder geschrieben und mithilfe des zweiten Konstruktors dekodiert, den wir oben hinzugefügt haben.

Optional können wir die folgende Methode einschließen, um alle Optionen beim Schreiben von Daten in das Pasteboard zu definieren:

[Export ("writingOptionsForType:pasteboard:"), CompilerGenerated]
public virtual NSPasteboardWritingOptions GetWritingOptionsForType (string type, NSPasteboard pasteboard) {
    return NSPasteboardWritingOptions.WritingPromised;
}

Derzeit ist nur die WritingPromised Option verfügbar und sollte verwendet werden, wenn ein bestimmter Typ nur zugesagt und nicht tatsächlich in das Pasteboard geschrieben wird. Weitere Informationen finden Sie im Abschnitt "Zugesagte Daten " weiter oben.

Mit diesen Methoden kann der folgende Code verwendet werden, um unsere benutzerdefinierte Klasse in das Pasteboard zu schreiben:

// Get the standard pasteboard
var pasteboard = NSPasteboard.GeneralPasteboard;

// Empty the current contents
pasteboard.ClearContents();

// Add info to the pasteboard
pasteboard.WriteObjects (new ImageInfo[] { Info });

Lesen aus dem Einfügebrett

Durch die Einhaltung der INSPasteboardReading Schnittstelle müssen drei Methoden verfügbar gemacht werden, damit die benutzerdefinierte Datenklasse aus dem Pasteboard gelesen werden kann.

Zunächst müssen wir dem Pasteboard mitteilen, welche Datentypdarstellungen die benutzerdefinierte Klasse aus der Zwischenablage lesen kann:

[Export ("readableTypesForPasteboard:")]
public static string[] GetReadableTypesForPasteboard (NSPasteboard pasteboard){
    string[] readableTypes = {"com.xamarin.image-info", "public.text"};
    return readableTypes;
}

Auch hier werden diese als einfache UTIs definiert und sind die gleichen Typen, die wir im Abschnitt "Schreiben in das Pasteboard " oben definiert haben.

Als Nächstes müssen wir dem Pasteboard mitteilen , wie jede der UTI-Typen mithilfe der folgenden Methode gelesen wird:

[Export ("readingOptionsForType:pasteboard:")]
public static NSPasteboardReadingOptions GetReadingOptionsForType (string type, NSPasteboard pasteboard) {

    // Take action based on the requested type
    switch (type) {
    case "com.xamarin.image-info":
        return NSPasteboardReadingOptions.AsKeyedArchive;
    case "public.text":
        return NSPasteboardReadingOptions.AsString;
    }

    // Default to property list
    return NSPasteboardReadingOptions.AsPropertyList;
}

Für den com.xamarin.image-info Typ geben wir dem Pasteboard an, das Schlüssel-Wert-Paar zu decodieren, das wir beim NSKeyedArchiver Schreiben der Klasse in das Pasteboard erstellt haben, indem wir den initWithCoder: Konstruktor aufrufen, den wir der Klasse hinzugefügt haben.

Schließlich müssen wir die folgende Methode hinzufügen, um die anderen UTI-Datendarstellungen aus dem Pasteboard zu lesen:

[Export ("initWithPasteboardPropertyList:ofType:")]
public NSObject InitWithPasteboardPropertyList (NSObject propertyList, string type) {

    // Take action based on the requested type
    switch (type) {
    case "public.text":
        return new ImageInfo();
    }

    // Failure, return null
    return null;
}

Mit allen diesen Methoden kann die benutzerdefinierte Datenklasse mithilfe des folgenden Codes aus dem Pasteboard gelesen werden:

// Initialize the pasteboard
NSPasteboard pasteboard = NSPasteboard.GeneralPasteboard;
var classArrayPtrs = new [] { Class.GetHandle (typeof(ImageInfo)) };
NSArray classArray = NSArray.FromIntPtrs (classArrayPtrs);

// NOTE: Sending messages directly to the base Objective-C API because of this defect:
// https://bugzilla.xamarin.com/show_bug.cgi?id=31760
// Check to see if image info is on the pasteboard
ok = bool_objc_msgSend_IntPtr_IntPtr (pasteboard.Handle, Selector.GetHandle ("canReadObjectForClasses:options:"), classArray.Handle, IntPtr.Zero);

if (ok) {
    // Read the image off of the pasteboard
    NSObject [] objectsToPaste = NSArray.ArrayFromHandle<Foundation.NSObject>(IntPtr_objc_msgSend_IntPtr_IntPtr (pasteboard.Handle, Selector.GetHandle ("readObjectsForClasses:options:"), classArray.Handle, IntPtr.Zero));
    ImageInfo info = (ImageInfo)objectsToPaste[0];
}

Verwenden eines NSPasteboardItem

Es kann vorkommen, dass Sie benutzerdefinierte Elemente in das Einfügebrett schreiben müssen, das nicht die Erstellung einer benutzerdefinierten Klasse garantiert oder Sie Daten in einem gemeinsamen Format bereitstellen möchten, nur wie erforderlich. Für diese Situationen können Sie eine NSPasteboardItem.

Eine NSPasteboardItem bietet eine feine Kontrolle über die Daten, die in das Einfügebrett geschrieben werden und für temporären Zugriff ausgelegt sind – es sollte nach dem Schreiben in das Pasteboard entfernt werden.

Schreiben von Daten

Um Ihre benutzerdefinierten Daten in eine NSPasteboardItem zu schreiben, müssen Sie einen benutzerdefinierten NSPasteboardItemDataProviderCode bereitstellen. Fügen Sie dem Projekt eine neue Klasse hinzu, und rufen Sie sie ImageInfoDataProvider.cs auf. Bearbeiten Sie die Datei, und sehen Sie wie folgt aus:

using System;
using AppKit;
using Foundation;

namespace MacCopyPaste
{
    [Register("ImageInfoDataProvider")]
    public class ImageInfoDataProvider : NSPasteboardItemDataProvider
    {
        #region Computed Properties
        public string Name { get; set;}
        public string ImageType { get; set;}
        #endregion

        #region Constructors
        [Export ("init")]
        public ImageInfoDataProvider ()
        {
        }

        public ImageInfoDataProvider (string name, string imageType)
        {
            // Initialize
            this.Name = name;
            this.ImageType = imageType;
        }

        protected ImageInfoDataProvider (NSObjectFlag t){
        }

        protected internal ImageInfoDataProvider (IntPtr handle){

        }
        #endregion

        #region Override Methods
        [Export ("pasteboardFinishedWithDataProvider:")]
        public override void FinishedWithDataProvider (NSPasteboard pasteboard)
        {
            
        }

        [Export ("pasteboard:item:provideDataForType:")]
        public override void ProvideDataForType (NSPasteboard pasteboard, NSPasteboardItem item, string type)
        {

            // Take action based on the type
            switch (type) {
            case "public.text":
                // Encode the data to string 
                item.SetStringForType(string.Format("{0}.{1}", Name, ImageType),type);
                break;
            }

        }
        #endregion
    }
}

Wie bei der benutzerdefinierten Datenklasse müssen wir die Register Und-Direktiven Export verwenden, um sie verfügbar Objective-Czu machen. Die Klasse muss von NSPasteboardItemDataProvider der Klasse erben und die FinishedWithDataProvider methoden ProvideDataForType implementieren.

Verwenden Sie die ProvideDataForType Methode, um die Daten bereitzustellen, die wie NSPasteboardItem folgt umschlossen werden:

[Export ("pasteboard:item:provideDataForType:")]
public override void ProvideDataForType (NSPasteboard pasteboard, NSPasteboardItem item, string type)
{

    // Take action based on the type
    switch (type) {
    case "public.text":
        // Encode the data to string 
        item.SetStringForType(string.Format("{0}.{1}", Name, ImageType),type);
        break;
    }

}

In diesem Fall speichern wir zwei Informationen zu unserem Bild (Name und ImageType) und schreiben diese in eine einfache Zeichenfolge (public.text).

Geben Sie die Daten in das Pasteboard ein, verwenden Sie den folgenden Code:

// Get the standard pasteboard
var pasteboard = NSPasteboard.GeneralPasteboard;

// Using a Pasteboard Item
NSPasteboardItem item = new NSPasteboardItem();
string[] writableTypes = {"public.text"};

// Add a data provider to the item
ImageInfoDataProvider dataProvider = new ImageInfoDataProvider (Info.Name, Info.ImageType);
var ok = item.SetDataProviderForTypes (dataProvider, writableTypes);

// Save to pasteboard
if (ok) {
    pasteboard.WriteObjects (new NSPasteboardItem[] { item });
}

Lesen von Daten

Verwenden Sie den folgenden Code, um die Daten aus dem Pasteboard zurückzulesen:

// Initialize the pasteboard
NSPasteboard pasteboard = NSPasteboard.GeneralPasteboard;
Class [] classArray  = { new Class ("NSImage") };

bool ok = pasteboard.CanReadObjectForClasses (classArray, null);
if (ok) {
    // Read the image off of the pasteboard
    NSObject [] objectsToPaste = pasteboard.ReadObjectsForClasses (classArray, null);
    NSImage image = (NSImage)objectsToPaste[0];

    // Do something with data
    ...
}
            
Class [] classArray2 = { new Class ("ImageInfo") };
ok = pasteboard.CanReadObjectForClasses (classArray2, null);
if (ok) {
    // Read the image off of the pasteboard
    NSObject [] objectsToPaste = pasteboard.ReadObjectsForClasses (classArray2, null);
    
    // Do something with data
    ...
}

Zusammenfassung

Dieser Artikel hat einen detaillierten Blick auf die Arbeit mit dem Pasteboard in einer Xamarin.Mac-Anwendung unternommen, um Kopier- und Einfügevorgänge zu unterstützen. Zunächst wurde ein einfaches Beispiel eingeführt, um Sie mit Standard-Pasteboards-Vorgängen vertraut zu machen. Als Nächstes hat es einen detaillierten Blick auf das Pasteboard und das Lesen und Schreiben von Daten darauf gedauert. Schließlich wurde die Verwendung eines benutzerdefinierten Datentyps untersucht, um das Kopieren und Einfügen komplexer Datentypen in einer App zu unterstützen.