Copier et coller dans Xamarin.Mac
Cet article traite de l’utilisation du collage pour fournir une copie et un collage dans une application Xamarin.Mac. Il montre comment utiliser des types de données standard qui peuvent être partagés entre plusieurs applications et comment prendre en charge des données personnalisées au sein d’une application donnée.
Vue d’ensemble
Lorsque vous utilisez C# et .NET dans une application Xamarin.Mac, vous avez accès à la même prise en charge du collage (copie et collage) qu’un développeur travaillant.Objective-C
Dans cet article, nous allons couvrir les deux principales façons d’utiliser le collage dans une application Xamarin.Mac :
- Types de données standard : étant donné que les opérations de collage sont généralement effectuées entre deux applications non liées, aucune application ne connaît les types de données pris en charge par l’autre. Pour optimiser le potentiel de partage, le collage peut contenir plusieurs représentations d’un élément donné (à l’aide d’un ensemble standard de types de données communs), ce qui permet à l’application consommatrice de choisir la version la mieux adaptée à ses besoins.
- Données personnalisées : pour prendre en charge la copie et le collage de données complexes au sein de votre Xamarin.Mac, vous pouvez définir un type de données personnalisé qui sera géré par le collage. Par exemple, une application de dessin vectoriel qui permet à l’utilisateur de copier et coller des formes complexes composées de plusieurs types de données et points.
Dans cet article, nous allons aborder les principes fondamentaux de l’utilisation du collage dans une application Xamarin.Mac pour prendre en charge les opérations de copie et de collage. Il est fortement suggéré que vous travaillez tout d’abord dans l’article Hello, Mac , en particulier les sections Introduction to Xcode and Interface Builder et Outlets and Actions , car elle couvre les concepts et techniques clés que nous utiliserons dans cet article.
Vous pouvez également examiner les classes /méthodes C# exposantes dans Objective-C la section du document interne Xamarin.Mac , ainsi que les Register
Export
attributs utilisés pour connecter vos classes C# à des objets et des Objective-C éléments d’interface utilisateur.
Prise en main du collage
Le collage présente un mécanisme standardisé permettant d’échanger des données au sein d’une application donnée ou entre des applications. L’utilisation classique d’un collage dans une application Xamarin.Mac consiste à gérer les opérations de copie et de collage, mais un certain nombre d’autres opérations sont également prises en charge (par exemple, glisser-déplacer et services d’application).
Pour vous aider rapidement, nous allons commencer par une introduction simple et pratique à l’utilisation de collages dans une application Xamarin.Mac. Plus tard, nous allons fournir une explication détaillée du fonctionnement du collage et des méthodes utilisées.
Pour cet exemple, nous allons créer une application simple basée sur des documents qui gère une fenêtre contenant une vue d’image. L’utilisateur peut copier et coller des images entre des documents de l’application et vers ou depuis d’autres applications ou plusieurs fenêtres à l’intérieur de la même application.
Création du projet Xamarin
Tout d’abord, nous allons créer une application Xamarin.Mac basée sur un document pour laquelle nous ajouterons la prise en charge de la copie et du collage.
Effectuez les actions suivantes :
Démarrez Visual Studio pour Mac et cliquez sur le lien Nouveau projet...
Sélectionnez Application Cacao d’application> Mac>, puis cliquez sur le bouton Suivant :
Entrez le nom du projet et conservez
MacCopyPaste
tout le reste comme valeur par défaut. Cliquez sur Suivant :Cliquez sur le bouton Créer :
Ajouter un NSDocument
Ensuite, nous allons ajouter une classe personnalisée NSDocument
qui servira de stockage en arrière-plan pour l’interface utilisateur de l’application. Il contient un affichage image unique et sait comment copier une image de l’affichage dans le collage par défaut et comment prendre une image à partir du collage par défaut et l’afficher dans l’affichage image.
Cliquez avec le bouton droit sur le projet Xamarin.Mac dans le panneau Solution, puis sélectionnez Ajouter>un nouveau fichier..
Entrez ImageDocument
comme Nom, puis cliquez sur le bouton Nouveau. Modifiez la classe ImageDocument.cs et faites-la ressembler à ce qui suit :
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
}
}
Examinons en détail certains du code ci-dessous.
Le code suivant fournit une propriété permettant de tester l’existence de données d’image sur le collage par défaut, si une image est disponible, true
est retournée sinon false
:
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);
}
}
Le code suivant copie une image de la vue d’image jointe dans le collage par défaut :
[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 });
}
}
}
Le code suivant colle une image à partir du collage par défaut et l’affiche dans la vue d’image jointe (si le collage contient une image valide) :
[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]
}
}
Avec ce document en place, nous allons créer l’interface utilisateur de l’application Xamarin.Mac.
Création de l’interface utilisateur
Double-cliquez sur le fichier Main.storyboard pour l’ouvrir dans Xcode. Ensuite, ajoutez une barre d’outils et une image et configurez-les comme suit :
Ajoutez une copie et collez l’élément de barre d’outils Image à gauche de la barre d’outils. Nous allons les utiliser comme raccourcis pour copier et coller à partir du menu Modifier. Ensuite, ajoutez quatre éléments de barre d’outils Image à droite de la barre d’outils. Nous allons les utiliser pour remplir correctement l’image avec certaines images par défaut.
Pour plus d’informations sur l’utilisation des barres d’outils, consultez notre documentation sur les barres d’outils .
Nous allons ensuite exposer les points de sortie et actions suivants pour nos éléments de barre d’outils et l’image bien :
Pour plus d’informations sur l’utilisation des points de vente et des actions, consultez la section Points de vente et actions de notre documentation Hello, Mac .
Activation de l’interface utilisateur
Avec notre interface utilisateur créée dans Xcode et notre élément d’interface utilisateur exposé via des points de sortie et des actions, nous devons ajouter le code pour activer l’interface utilisateur. Double-cliquez sur le fichier ImageWindow.cs dans le Panneau Solution et faites-le ressembler à ce qui suit :
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
}
}
Examinons ce code en détail ci-dessous.
Tout d’abord, nous exposons une instance de la ImageDocument
classe que nous avons créée ci-dessus :
private ImageDocument _document;
...
[Export ("Document")]
public ImageDocument Document {
get { return _document; }
set {
WillChangeValue ("Document");
_document = value;
DidChangeValue ("Document");
}
}
En utilisant Export
, WillChangeValue
et DidChangeValue
, nous avons configuré la Document
propriété pour autoriser le codage clé-valeur et la liaison de données dans Xcode.
Nous exposons également l’image à partir de l’image que nous avons ajoutée à notre interface utilisateur dans Xcode avec la propriété suivante :
public ViewController ImageViewController {
get { return ContentViewController as ViewController; }
}
public NSImage Image {
get {
return ImageViewController.Image;
}
set {
ImageViewController.Image = value;
}
}
Lorsque la fenêtre principale est chargée et affichée, nous créons une instance de notre ImageDocument
classe et attachons l’image de l’interface utilisateur correctement à celle-ci avec le code suivant :
public override void AwakeFromNib ()
{
base.AwakeFromNib ();
// Create a new document instance
Document = new ImageDocument ();
// Attach to image view
Document.ImageView = ImageViewController.ContentView;
}
Enfin, en réponse à l’utilisateur en cliquant sur les éléments de la barre d’outils copier-coller, nous appelons l’instance de la ImageDocument
classe pour effectuer le travail réel :
partial void CopyImage (NSObject sender) {
Document.CopyImage(sender);
}
partial void PasteImage (Foundation.NSObject sender) {
Document.PasteImage(sender);
}
Activation des menus Fichier et Édition
La dernière chose à faire est d’activer l’élément de menu Nouveau à partir du menu Fichier (pour créer de nouvelles instances de notre fenêtre principale) et d’activer les éléments de menu Couper, Copier et Coller à partir du menu Modifier .
Pour activer l’élément de menu Nouveau , modifiez le fichier AppDelegate.cs et ajoutez le code suivant :
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);
}
Pour plus d’informations, consultez la section Working with Multiple Windows de notre documentation Windows .
Pour activer les éléments de menu Couper, Copier et Coller , modifiez le fichier AppDelegate.cs et ajoutez le code suivant :
[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);
}
Pour chaque élément de menu, nous obtenons la fenêtre actuelle, la plus haute, la fenêtre clé et la castons dans notre ImageWindow
classe :
var window = NSApplication.SharedApplication.KeyWindow as ImageWindow;
À partir de là, nous appelons l’instance ImageDocument
de classe de cette fenêtre pour gérer les actions de copie et de collage. Par exemple :
window.Document.CopyImage (sender);
Nous voulons uniquement que les éléments de menu Couper, Copier et Coller soient accessibles s’il existe des données d’image sur le collage par défaut ou dans l’image bien de la fenêtre active actuelle.
Nous allons ajouter un fichier EditMenuDelegate.cs au projet Xamarin.Mac et le faire ressembler à ce qui suit :
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
}
}
Là encore, nous obtenons la fenêtre actuelle la plus haute et nous utilisons son ImageDocument
instance de classe pour voir si les données d’image requises existent. Ensuite, nous utilisons la MenuWillHighlightItem
méthode pour activer ou désactiver chaque élément en fonction de cet état.
Modifiez le fichier AppDelegate.cs et faites en sorte que la DidFinishLaunching
méthode ressemble à ce qui suit :
public override void DidFinishLaunching (NSNotification notification)
{
// Disable automatic item enabling on the Edit menu
EditMenu.AutoEnablesItems = false;
EditMenu.Delegate = new EditMenuDelegate ();
}
Tout d’abord, nous désactivons l’activation et la désactivation automatiques des éléments de menu dans le menu Modifier. Ensuite, nous attachons une instance de la EditMenuDelegate
classe que nous avons créée ci-dessus.
Pour plus d’informations, consultez notre documentation menus .
Test de l’application
Avec tout ce qui est en place, nous sommes prêts à tester l’application. Générez et exécutez l’application et l’interface principale s’affiche :
Si vous ouvrez le menu Modifier, notez que couper, copier et coller sont désactivés, car il n’existe aucune image dans l’image ou dans le collage par défaut :
Si vous ajoutez une image à l’image et rouvrez le menu Modifier, les éléments seront désormais activés :
Si vous copiez l’image et sélectionnez Nouveau dans le menu fichier, vous pouvez coller cette image dans la nouvelle fenêtre :
Dans les sections suivantes, nous allons examiner en détail l’utilisation du collage dans une application Xamarin.Mac.
À propos du collage
Dans macOS (anciennement OS X), le collage (NSPasteboard
) fournit la prise en charge de plusieurs processus serveur tels que Copier et Coller, Glisser-déplacer et Application Services. Dans les sections suivantes, nous allons examiner de plus près plusieurs concepts de collage de clé.
Qu’est-ce qu’un collage ?
La NSPasteboard
classe fournit un mécanisme standardisé pour échanger des informations entre des applications ou dans une application donnée. La fonction principale d’un collage est de gérer les opérations de copie et de collage :
- Lorsque l’utilisateur sélectionne un élément dans une application et utilise l’élément de menu Couper ou Copier , une ou plusieurs représentations de l’élément sélectionné sont placées sur le collage.
- Lorsque l’utilisateur utilise l’élément de menu Coller (dans la même application ou une autre), la version des données qu’il peut gérer est copiée à partir du collage et ajoutée à l’application.
Les opérations de recherche, de glisser-déplacer, de glisser-déplacer et de services d’application sont moins évidentes :
- Lorsque l’utilisateur lance une opération de glissement, les données de glissement sont copiées dans le collage. Si l’opération de glissement se termine par une liste déroulante sur une autre application, cette application copie les données à partir du collage.
- Pour les services de traduction, les données à traduire sont copiées dans le collage par l’application demandée. Le service d’application récupère les données à partir du collage, effectue la traduction, puis colle les données dans le collage.
Dans leur forme la plus simple, les collages sont utilisés pour déplacer des données à l’intérieur d’une application donnée ou entre des applications et existe dans une zone de mémoire globale spéciale en dehors du processus de l’application. Bien que les concepts des collages soient facilement saisis, plusieurs détails plus complexes doivent être pris en compte. Celles-ci seront abordées en détail ci-dessous.
Collages nommés
Un collage peut être public ou privé et peut être utilisé à diverses fins au sein d’une application ou entre plusieurs applications. macOS fournit plusieurs collages standard, chacun avec une utilisation spécifique et bien définie :
NSGeneralPboard
- Le collage par défaut pour les opérations Couper, Copier et Coller .NSRulerPboard
- Prend en charge les opérations Couper, Copier et Coller sur les règles.NSFontPboard
- Prend en charge les opérations Couper, Copier et Coller sur lesNSFont
objets.NSFindPboard
- Prend en charge les panneaux de recherche spécifiques à l’application qui peuvent partager du texte de recherche.NSDragPboard
- Prend en charge les opérations glisser-déplacer .
Dans la plupart des cas, vous allez utiliser l’un des collages définis par le système. Toutefois, il peut y avoir des situations qui vous obligent à créer vos propres collages. Dans ces situations, vous pouvez utiliser la FromName (string name)
méthode de la NSPasteboard
classe pour créer un collage personnalisé avec le nom donné.
Si vous le souhaitez, vous pouvez appeler la CreateWithUniqueName
méthode de la NSPasteboard
classe pour créer un collage nommé de manière unique.
Éléments de collage
Chaque élément de données qu’une application écrit dans un collage est considéré comme un élément pasteboard et un collage peut contenir plusieurs éléments en même temps. De cette façon, une application peut écrire plusieurs versions des données copiées dans un collage (par exemple, du texte brut et du texte mis en forme) et l’application de récupération peut lire uniquement les données qu’elle peut traiter (par exemple, le texte brut uniquement).
Représentations de données et identificateurs de type uniforme
Les opérations de collage se produisent généralement entre deux applications (ou plus) qui n’ont aucune connaissance des autres ou les types de données que chacun peut gérer. Comme indiqué dans la section ci-dessus, pour maximiser le potentiel de partage des informations, un collage peut contenir plusieurs représentations des données copiées et collées.
Chaque représentation est identifiée via un identificateur de type uniforme (UTI), qui n’est rien de plus qu’une chaîne simple qui identifie de manière unique le type de date présenté (pour plus d’informations, consultez la documentation Vue d’ensemble des identificateurs de type uniforme d’Apple).
Si vous créez un type de données personnalisé (par exemple, un objet de dessin dans une application de dessin vectoriel), vous pouvez créer votre propre UTI pour l’identifier de manière unique dans les opérations de copie et de collage.
Lorsqu’une application se prépare à coller des données copiées à partir d’un collage, elle doit trouver la représentation qui correspond le mieux à ses capacités (le cas échéant). En règle générale, il s’agit du type le plus riche disponible (par exemple du texte mis en forme pour une application de traitement de texte), en rebastant vers les formulaires les plus simples disponibles en fonction des besoins (texte brut pour un éditeur de texte simple).
Données promises
En règle générale, vous devez fournir autant de représentations des données copiées que possible pour optimiser le partage entre les applications. Toutefois, en raison de contraintes de temps ou de mémoire, il peut être difficile d’écrire réellement chaque type de données dans le collage.
Dans ce cas, vous pouvez placer la première représentation des données sur le collage et l’application de réception peut demander une représentation différente, qui peut être générée à la volée juste avant l’opération de collage.
Lorsque vous placez l’élément initial dans le collage, vous spécifiez qu’une ou plusieurs des autres représentations disponibles sont fournies par un objet conforme à l’interface NSPasteboardItemDataProvider
. Ces objets fournissent les représentations supplémentaires à la demande, comme demandé par l’application de réception.
Nombre de modifications
Chaque collage conserve un nombre de modifications qui incrémente chaque fois qu’un nouveau propriétaire est déclaré. Une application peut déterminer si le contenu du collage a changé depuis la dernière fois qu’il l’a examiné en case activée la valeur du nombre de modifications.
Utilisez les méthodes et ClearContents
les ChangeCount
méthodes de la NSPasteboard
classe pour modifier le nombre de modifications d’un collage donné.
Copie de données dans un collage
Vous effectuez une opération de copie en accédant d’abord à un collage, en désactivant tout contenu existant et en écrivant autant de représentations des données que nécessaire au collage.
Par exemple :
// 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});
En règle générale, vous allez simplement écrire dans le collage général, comme nous l’avons fait dans l’exemple ci-dessus. Tout objet que vous envoyez à la WriteObjects
méthode doit être conforme à l’interface INSPasteboardWriting
. Plusieurs classes intégrées (telles que NSString
, , NSImage
, NSURL
NSColor
, , NSAttributedString
et NSPasteboardItem
) sont automatiquement conformes à cette interface.
Si vous écrivez une classe de données personnalisée dans le collage, elle doit être conforme à l’interface INSPasteboardWriting
ou être encapsulée dans une instance de la NSPasteboardItem
classe (voir la section Types de données personnalisés ci-dessous).
Lecture de données à partir d’un collage
Comme indiqué ci-dessus, pour maximiser le potentiel de partage de données entre les applications, plusieurs représentations des données copiées peuvent être écrites dans le collage. Il incombe à l’application de réception de sélectionner la version la plus riche possible pour ses fonctionnalités (le cas échéant).
Opération de collage simple
Vous lisez des données à partir du collage à l’aide de la ReadObjectsForClasses
méthode. Il nécessite deux paramètres :
- Tableau de types de
NSObject
classes basés que vous souhaitez lire à partir du collage. Vous devez d’abord commander cela avec le type de données le plus souhaité, avec tous les autres types en préférence décroissante. - Dictionnaire contenant des contraintes supplémentaires (telles que la limitation à des types de contenu d’URL spécifiques) ou un dictionnaire vide si aucune autre contrainte n’est requise.
La méthode retourne un tableau d’éléments répondant aux critères que nous avons passés et contient donc au maximum le même nombre de types de données demandés. Il est également possible qu’aucun des types demandés ne soit présent et qu’un tableau vide soit retourné.
Par exemple, le code suivant case activée pour voir s’il existe un NSImage
collage général et l’affiche dans une image correctement si elle le fait :
[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];
}
}
Demande de plusieurs types de données
En fonction du type d’application Xamarin.Mac en cours de création, il peut être en mesure de gérer plusieurs représentations des données collées. Dans ce cas, il existe deux scénarios pour récupérer des données à partir du collage :
- Effectuez un appel unique à la
ReadObjectsForClasses
méthode et fournissez un tableau de toutes les représentations souhaitées (dans l’ordre préféré). - Effectuez plusieurs appels à la
ReadObjectsForClasses
méthode qui demandent un tableau de types différent à chaque fois.
Pour plus d’informations sur la récupération des données à partir d’un collage, consultez la section Opération de collage simple ci-dessus.
Vérification des types de données existants
Il peut arriver que vous souhaitiez case activée si un collage contient une représentation de données donnée sans réellement lire les données à partir du collage (par exemple, l’activation de l’élément de menu Coller uniquement quand des données valides existent).
Appelez la CanReadObjectForClasses
méthode du collage pour voir s’il contient un type donné.
Par exemple, le code suivant détermine si le collage général contient une NSImage
instance :
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);
}
}
Lecture d’URL à partir du collage
En fonction de la fonction d’une application Xamarin.Mac donnée, il peut être nécessaire de lire des URL à partir d’un collage, mais uniquement s’ils répondent à un ensemble donné de critères (par exemple, pointer vers des fichiers ou des URL d’un type de données spécifique). Dans ce cas, vous pouvez spécifier des critères de recherche supplémentaires à l’aide du deuxième paramètre des méthodes ou ReadObjectsForClasses
des CanReadObjectForClasses
méthodes.
Types de données personnalisés
Il arrive parfois que vous deviez enregistrer vos propres types personnalisés dans le collage à partir d’une application Xamarin.Mac. Par exemple, une application de dessin vectoriel qui permet à l’utilisateur de copier et coller des objets de dessin.
Dans ce cas, vous devez concevoir votre classe personnalisée de données afin qu’elle hérite et qu’elle soit NSObject
conforme à quelques interfaces (INSCoding
INSPasteboardWriting
et INSPasteboardReading
). Si vous le souhaitez, vous pouvez utiliser un NSPasteboardItem
pour encapsuler les données à copier ou coller.
Ces deux options seront abordées en détail ci-dessous.
Utilisation d’une classe personnalisée
Dans cette section, nous allons développer l’exemple d’application simple que nous avons créé au début de ce document et ajouter une classe personnalisée pour suivre les informations sur l’image que nous copions et collons entre les fenêtres.
Ajoutez une nouvelle classe au projet et appelez-la ImageInfo.cs. Modifiez le fichier et faites-le ressembler à ce qui suit :
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
}
}
Dans les sections suivantes, nous allons examiner cette classe en détail.
Héritage et interfaces
Avant qu’une classe de données personnalisée puisse être écrite ou lue à partir d’un collage, elle doit être conforme aux interfaces et INSPasteboardReading
aux INSPastebaordWriting
interfaces. En outre, il doit hériter et NSObject
également se conformer à l’interface INSCoding
:
[Register("ImageInfo")]
public class ImageInfo : NSObject, INSCoding, INSPasteboardWriting, INSPasteboardReading
...
La classe doit également être exposée à l’utilisation de Objective-C la Register
directive et doit exposer toutes les propriétés ou méthodes requises à l’aide Export
de . Par exemple :
[Export("name")]
public string Name { get; set; }
[Export("imageType")]
public string ImageType { get; set; }
Nous exposons les deux champs de données que cette classe contiendra : le nom de l’image et son type (jpg, png, etc.).
Pour plus d’informations, consultez les classes /méthodes C# exposantes dans Objective-C la section de la documentation interne Xamarin.Mac, elle explique les attributs et Export
les Register
attributs utilisés pour connecter vos classes C# à des objets et des Objective-C éléments d’interface utilisateur.
Constructeurs
Deux constructeurs (correctement exposés à Objective-C) seront requis pour notre classe de données personnalisée afin qu’elle puisse être lue à partir d’un collage :
[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 ();
}
Tout d’abord, nous exposons le constructeur vide sous la méthode par défaut Objective-C de init
.
Ensuite, nous exposons un NSCoding
constructeur conforme qui sera utilisé pour créer une nouvelle instance de l’objet à partir du collage lors du collage sous le nom exporté de initWithCoder
.
Ce constructeur prend un NSCoder
(tel qu’il est créé par un NSKeyedArchiver
écrit dans le collage), extrait les données jumelées clé/valeur et les enregistre dans les champs de propriété de la classe de données.
Écriture dans le collage
En respectant l’interface INSPasteboardWriting
, nous devons exposer deux méthodes, et éventuellement une troisième méthode, afin que la classe puisse être écrite dans le collage.
Tout d’abord, nous devons indiquer au collage les représentations de type de données dans lesquelles la classe personnalisée peut être écrite :
[Export ("writableTypesForPasteboard:")]
public virtual string[] GetWritableTypesForPasteboard (NSPasteboard pasteboard) {
string[] writableTypes = {"com.xamarin.image-info", "public.text"};
return writableTypes;
}
Chaque représentation est identifiée via un identificateur de type uniforme (UTI), qui n’est rien de plus qu’une chaîne simple qui identifie de manière unique le type de données présenté (pour plus d’informations, consultez la documentation Vue d’ensemble des identificateurs de type uniforme d’Apple).
Pour notre format personnalisé, nous créons notre propre UTI : « com.xamarin.image-info » (notez qu’il s’agit d’une notation inverse comme un identificateur d’application). Notre classe est également capable d’écrire une chaîne standard dans le collage (public.text
).
Ensuite, nous devons créer l’objet dans le format demandé qui est réellement écrit dans le collage :
[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;
}
Pour le public.text
type, nous renvoyons un objet simple et mis en forme NSString
. Pour le type personnalisé com.xamarin.image-info
, nous utilisons un NSKeyedArchiver
et l’interface NSCoder
pour encoder la classe de données personnalisée dans une archive jumelée clé/valeur. Nous devons implémenter la méthode suivante pour gérer réellement l’encodage :
[Export ("encodeWithCoder:")]
public void EncodeTo (NSCoder encoder) {
// Encode data
encoder.Encode(new NSString(Name),"name");
encoder.Encode(new NSString(ImageType),"imageType");
}
Les paires clé/valeur individuelles sont écrites dans l’encodeur et seront décodées à l’aide du deuxième constructeur que nous avons ajouté ci-dessus.
Si vous le souhaitez, nous pouvons inclure la méthode suivante pour définir toutes les options lors de l’écriture de données dans le collage :
[Export ("writingOptionsForType:pasteboard:"), CompilerGenerated]
public virtual NSPasteboardWritingOptions GetWritingOptionsForType (string type, NSPasteboard pasteboard) {
return NSPasteboardWritingOptions.WritingPromised;
}
Actuellement, seule l’option WritingPromised
est disponible et doit être utilisée lorsqu’un type donné n’est promis qu’et n’est pas réellement écrit dans le collage. Pour plus d’informations, consultez la section Données promises ci-dessus.
Avec ces méthodes en place, le code suivant peut être utilisé pour écrire notre classe personnalisée dans le collage :
// Get the standard pasteboard
var pasteboard = NSPasteboard.GeneralPasteboard;
// Empty the current contents
pasteboard.ClearContents();
// Add info to the pasteboard
pasteboard.WriteObjects (new ImageInfo[] { Info });
Lecture à partir du collage
En respectant l’interface INSPasteboardReading
, nous devons exposer trois méthodes afin que la classe de données personnalisée puisse être lue à partir du collage.
Tout d’abord, nous devons indiquer au collage les représentations de type de données que la classe personnalisée peut lire à partir du Presse-papiers :
[Export ("readableTypesForPasteboard:")]
public static string[] GetReadableTypesForPasteboard (NSPasteboard pasteboard){
string[] readableTypes = {"com.xamarin.image-info", "public.text"};
return readableTypes;
}
Là encore, ils sont définis comme des UTIs simples et sont les mêmes types que ceux que nous avons définis dans la section Écriture dans la section Coller au tableau ci-dessus.
Ensuite, nous devons indiquer au collage comment chacun des types UTI sera lu à l’aide de la méthode suivante :
[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;
}
Pour le com.xamarin.image-info
type, nous demandons au collage de décoder la paire clé/valeur que nous avons créée avec la NSKeyedArchiver
classe lors de l’écriture de la classe dans le collage en appelant le initWithCoder:
constructeur que nous avons ajouté à la classe.
Enfin, nous devons ajouter la méthode suivante pour lire les autres représentations de données UTI à partir du collage :
[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;
}
Avec toutes ces méthodes en place, la classe de données personnalisée peut être lue à partir du collage à l’aide du code suivant :
// 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];
}
Utilisation d’un NSPasteboardItem
Il peut arriver que vous deviez écrire des éléments personnalisés dans le collage qui ne justifient pas la création d’une classe personnalisée ou que vous souhaitez fournir des données dans un format commun, uniquement si nécessaire. Pour ces situations, vous pouvez utiliser un NSPasteboardItem
.
Un NSPasteboardItem
contrôle précis sur les données écrites dans le collage et conçu pour un accès temporaire doit être supprimé une fois qu’il a été écrit dans le collage.
Écriture de données
Pour écrire vos données personnalisées dans un fichier NSPasteboardItem
personnalisé, vous devez fournir un fichier personnalisé NSPasteboardItemDataProvider
. Ajoutez une nouvelle classe au projet et appelez-la ImageInfoDataProvider.cs. Modifiez le fichier et faites-le ressembler à ce qui suit :
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
}
}
Comme nous l’avons fait avec la classe de données personnalisée, nous devons utiliser les directives et Export
les Register
utiliser pour l’exposer Objective-C. La classe doit hériter et NSPasteboardItemDataProvider
doit implémenter les méthodes et ProvideDataForType
les FinishedWithDataProvider
méthodes.
Utilisez la ProvideDataForType
méthode pour fournir les données qui seront encapsulées comme NSPasteboardItem
suit :
[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;
}
}
Dans ce cas, nous stockons deux informations sur notre image (Name et ImageType) et écrivons-les dans une chaîne simple (public.text
).
Tapez écrire les données dans le collage, utilisez le code suivant :
// 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 });
}
Lecture des données en cours
Pour lire les données à partir du collage, utilisez le code suivant :
// 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
...
}
Résumé
Cet article a examiné en détail l’utilisation du collage dans une application Xamarin.Mac pour prendre en charge les opérations de copie et de collage. Tout d’abord, il a introduit un exemple simple pour vous familiariser avec les opérations de collage standard. Ensuite, il a fallu un examen détaillé du collage et comment lire et écrire des données à partir de celui-ci. Enfin, il a examiné l’utilisation d’un type de données personnalisé pour prendre en charge la copie et le collage de types de données complexes au sein d’une application.