Clipboard
Data Formats
Before accessing the clipboard, it's important to understand the data format, represented by the DataFormat<T> class. It represents the format of a data item (e.g., text, HTML, PNG, etc.) and is used by various clipboard and drag-and-drop APIs.
A data format consists of a kind (Universal, Platform, or Application), an identifier, and a data type.
Data formats are considered equal if they have the same kind and identifier.
Universal Formats
Universal formats are cross-platform formats that Avalonia directly understands.
There are currently three universal formats:
| Format | Identifier | Type | Description |
|---|---|---|---|
DataFormat.Text | "Text" | string | Plain text data |
DataFormat.File | "File" | IStorageItem | A file or directory |
DataFormat.Bitmap | "Bitmap" | Bitmap | A bitmap image |
Platform Formats
Platform format is compatible only with the current platform that the application is running on (e.g., Windows, Linux, iOS, etc.). Its identifier should be a name understood by the underlying platform. Use this format only when you need direct interoperability with the target platform and have precise knowledge of its encoding or serialization.
Do not assume that a given identifier works for all platforms!
For example, the HTML format is named HTML format on Windows, text/html on Linux and Android, and public.html on macOS and iOS. Always verify the intended operating system before using a platform-specific format.
A platform format can be defined using DataFormat.CreateBytesPlatformFormat or DataFormat.CreateStringPlatformFormat, respectively using byte[] and string types. Avalonia does not perform automatic serialization.
Example:
if (OperatingSystem.IsMacOS())
{
var macOSHtmlFormat = DataFormat.CreateStringPlatformFormat("public.html");
}
Application Formats
An application format is specific to your application and works with all platforms that allow custom data formats. Its identifier is restricted to ASCII letters, digits, plus dot and dash symbols (A-Z, a-z, 0-9, ., -). This identifier will not be exposed directly to the underlying platform; instead, it will be internally prefixed to avoid conflicts with platform formats.
Use this format when you need to place application-specific data on the clipboard, for example, to share it between multiple instances of the program.
An application format can be defined using DataFormat.CreateBytesApplicationFormat or DataFormat.CreateStringApplicationFormat, respectively using byte[] and string types. Avalonia does not perform automatic serialization.
var myFormat = DataFormat.CreateBytesApplicationFormat("mycompany-myapp-myformat");
IClipboard
The IClipboard interface enables interaction with the system clipboard to set and retrieve text, image, and custom data formats.
An instance of IClipboard can be accessed through a TopLevel object:
var clipboard = window.Clipboard;
Reading
TryGetDataAsync()
The clipboard's content is read by retrieving an instance of IAsyncDataTransfer. This object is responsible for providing data items of various formats on demand (see the IAsyncDataTransfer section below).
The TryGetDataAsync method asynchronously retrieves an IAsyncDataTransfer object representing the clipboard's contents. If the clipboard is empty, null is returned.
using var data = await clipboard.TryGetDataAsync();
Since the clipboard's contents may change at any time, it is recommended to use the returned IAsyncDataTransfer instance as soon as possible; do not store it for later use. After all the necessary operations are done on the object, it must be disposed of by the caller; a using statement is therefore recommended.
Extension Methods
To retrieve data using a specific format, several extension methods are available. You can use the following for common formats, instead of TryGetDataAsync():
TryGetValueAsync(DataFormat<T>)returns a single value of typeTmatching the specified data format from the clipboard, ornullif none is present.TryGetValuesAsync(DataFormat<T>)returns multiple values of typeTmatching the specified data format from the clipboard, or an empty array if none is present.TryGetTextAsync()returns a singlestringvalue matching theDataFormat.Textformat, ornullif none is present.TryGetFileAsync()returns a singleIStorageItemobject matching theDataFormat.Fileformat, ornullif none is present.TryGetFilesAsync()returns multipleIStorageItemobjects matching theDataFormat.Fileformat, or an empty array if none is present.TryGetBitmapAsync()returns a singleBitmapimage matching theDataFormat.Bitmapformat, ornullif none is present.
If several values are present on the clipboard when the methods returning a single value are called, the first one is used.
Examples:
var text = await clipboard.TryGetTextAsync();
Console.WriteLine($"Clipboard text: {text}");
var file = await clipboard.TryGetFileAsync();
Console.WriteLine($"Clipboard file: {file?.Path}");
var bitmap = await clipboard.TryGetBitmapAsync();
Console.WriteLine($"Clipboard image: {bitmap?.PixelSize}");
Each of these extension methods calls TryGetDataAsync() under the hood. If you plan to use several of these in a row, consider calling TryGetDataAsync() once instead to obtain an IAsyncDataTransfer, then read the expected values from that object.
TryGetInProcessDataAsync()
This method retrieves the exact IAsyncDataTransfer instance previously placed on the clipboard by SetDataAsync() if it's still present. If the clipboard's content has changed, has been flushed, or if the platform does not support lazily provided values, this method returns null.
Calling this method avoids accessing the underlying platform's clipboard, which can be useful when fine-grained control is needed. For most scenarios, using TryGetDataAsync() is the preferred option.
This method is supported on Windows, macOS, and X11.
Writing
SetDataAsync()
To place data on the clipboard, call the IClipboard.SetDataAsync(IAsyncDataTransfer) method. It accepts an implementation of IAsyncDataTransfer that is responsible for providing data items of various formats on demand (see the IAsyncDataTransfer section below).
Example:
var data = new DataTransfer();
data.Add(DataTransferItem.CreateText("Copied from Avalonia!"));
await clipboard.SetDataAsync(data);
Placing a new object on the clipboard always clears any previous data.
Do not call Dispose() on the IAsyncDataTransfer object passed to SetDataAsync()! The instance must stay valid while it's on the clipboard. Avalonia takes ownership and automatically disposes of it once it's no longer in use.
Extension Methods
To write a single specific format, several extension methods are available for convenience. You can use the following for common formats:
SetValueAsync(DataFormat<T>, T)sets a single value of typeTwith the specified data format on the clipboard.SetValuesAsync(DataFormat<T>, IEnumerable<T>)sets multiple values of typeTwith the specified data formats on the clipboard.SetTextAsync(string)sets a singlestringvalue with theDataFormat.Textformat on the clipboard.SetFileAsync(IStorageItem)sets a singleIStorageItemobject with theDataFormat.Fileformat on the clipboard.SetFilesAsync(IEnumerable<IStorageItem>)sets multipleIStorageItemobjects with theDataFormat.Fileformat on the clipboard.SetBitmapAsync(Bitmap)sets a singleBitmapimage with theDataFormat.Bitmapformat on the clipboard.
ClearAsync()
Calling the ClearAsync() method clears the clipboard of all contents.
FlushAsync()
On Windows, macOS, and X11, the data is retrieved lazily on demand from the IAsyncDataTransfer placed on the clipboard.
If the Avalonia application terminates, the data becomes unavailable.
On Windows, calling FlushAsync() allows the system to query all the data present on the clipboard and persist it. On other platforms, this method does nothing.
IAsyncDataTransfer & IAsyncDataTransferItem
The IAsyncDataTransfer interface represents the contents of the clipboard and exposes the following properties:
Formats, returning a list ofDataFormatinstances representing all formats present inside the object.Items, returning a list ofIAsyncDataTransferIteminstances representing all items present inside the object.
The IAsyncDataTransferItem interface represents a single item inside an IAsyncDataTransfer and exposes the following members:
Formats, returning a list ofDataFormatinstances representing all formats present inside the object.TryGetRawAsync(DataFormat), used to retrieve a single value in a given data format asynchronously.
A single item can have multiple formats.
For example, rich text might be represented in RTF, HTML, and plain text.
Getting values
Raw
To read values from an IAsyncDataTransferItem object, call the TryGetRawAsync(DataFormat) method by specifying the requested data format.
The returned value is untyped (object).
Consider using the extension methods described below to get typed results.
Typed
Several extension methods are provided to retrieve typed values from IAsyncDataTransfer and IAsyncDataTransferItem:
TryGetValueAsync(DataFormat<T>)returns a single value of typeTmatching the specified data format, ornullif none is present.TryGetTextAsync()returns a singlestringvalue matching theDataFormat.Textformat, ornullif none is present.TryGetFileAsync()returns a singleIStorageItemobject matching theDataFormat.Fileformat, ornullif none is present.TryGetBitmapAsync()returns a singleBitmapimage matching theDataFormat.Bitmapformat, ornullif none is present.
When called on IAsyncDataTransfer, if multiple items match the requested format, the first is used.
In addition, the following extension methods exist only for IAsyncDataTransfer:
TryGetValuesAsync(DataFormat<T>)returns multiple values of typeTmatching the specified data format, or an empty array if none is present.TryGetFilesAsync()returns multipleIStorageItemobjects matching theDataFormat.Fileformat, or an empty array if none is present.
Implementation
DataTransfer & DataTransferItem
To provide values to write to the clipboard, both IAsyncDataTransfer and IAsyncDataTransferItem must be implemented.
Avalonia provides implementations of those interfaces with the DataTransfer and DataTransferItem types, respectively:
- The
DataTransferclass is a list of items. It provides anAdd(DataTransferItem)method used to add new items. - The
DataTransferItemclass can be considered a dictionary of format and value pairs. It provides aSet<T>(DataFormat, T)method used to set the value for a given format.
Example:
// Creates an item with both text and HTML formats.
var item = new DataTransferItem();
item.Set(DataFormat.Text, "From Avalonia!");
item.Set(DataFormat.CreateStringPlatformFormat("text/html"), "From <b>Avalonia</b>!");
// Adds the item to the DataTransfer.
var data = new DataTransfer();
data.Add(item);
The Set<T> method also has an overload Set<T>(DataFormat, Func<T>), allowing the value to be provided lazily.
For convenience, DataTransferItem provides methods to set the value for common formats:
SetText(string)sets astringvalue for theDataFormat.Textformat.SetFile(IStorageItem)sets anIStorageItemobject for theDataFormat.Fileformat.SetBitmap(Bitmap)sets aBitmapimage for theDataFormat.Bitmapformat.
Additionally, static factories exist to create items with a single format:
DataTransferItem.Create<T>(DataFormat<T>, T)for a given format.DataTransferItem.CreateText(string)for theDataFormat.Textformat.DataTransferItem.CreateFile(IStorageItem)for theDataFormat.Fileformat.DataTransferItem.CreateBitmap(Bitmap)for theDataFormat.Bitmapformat.
Custom
For advanced scenarios, you can implement IAsyncDataTransfer and IAsyncDataTransferItem manually. One possible use is to dynamically provide a variety of formats for a given item.
When writing the implementation, be certain that:
DataTransferandDataTransferItemare not enough for your needs.IAsyncDataTransfer.Formatscontains the formats of all items, without duplicates.- You are aware
IAsyncDataTransferItem.TryGetRawAsync()can be called from any thread and does not use the dispatcher. - You have considered implementing
IDataTransferandIDataTransferItem, as some platforms can only access the clipboard synchronously.
IAsyncDataTransferItem.TryGetRawAsync() may or may not be called on the UI thread depending on the underlying platform. Do not call anything on the UI thread, including via Dispatcher.Invoke/InvokeAsync. Doing so will result in deadlocks!
Have questions or feedback? Join the conversation below.