Windows 8 : the sharing contract in Metro / WinRT applications

, , 3 Comments

Metro applications introduce the use of contracts in your applications. You can think of them as “system interfaces” telling Windows: “my app is able to perform this operation“.

One of them, and I think the one which will be the most interesting, is the “Share contract” which enable sharing (how strange !) trough an application.

It works in pair with the “send contract” but in this post, we are going to focus on the share contract and describe what it is, how to put it in your app and how to use the shared data.

What is it ?

The windows 8’s sharing capability provide a way to the user to share data to the world. The sharing is done trough application which tells the system they are abble to do it. This is a three step process:

First, the user click on the share button (it is in the start menu) and the system ask what to share:

Then you have to select which application to use:

And finally a sharing screen is bringed. This one is specific to the application :

What can we share ?

At the time of the post, you can share – only – 6 different types of data. These types are represented in the StandardDataFormats class as static properties:

  • Bitmap: a bitmap represented by a stream of bytes. This one is provided by the system when you share a screenshot;
  • Html: text on the HTML format;
  • Rtf: text on the RTF format;
  • StorageItems: items which implements the IStorageItem interface. It seems to be media items located on a physical drive;
  • Text: raw text sharing;
  • Uri: you can share link with this format;

Each sharing operation can contains one item of each type listed above.

How to enable the sharing ?

The first thing to do is to tell the system that you application is sharing-enabled. This is done via the application manifest, named Package.appxmanifest by default. By double-clicking on it, you brings up the visual studio editor which lets you configure it. In your case, we are interested by the third tab named “Declarations”. We are going to declare to the system that our app is a share target.

As you can see, there is some configuration available:

  • You can tell which files type are enable to be shared with the app trough the “supported file types” section. Just type in the full extension with the dot, for example: “.png”;
  • You can tell which data formats your application can share. Just type in the name of the format, for example: “bitmap”;

How to get the data ?

Once this done, it’s time to write some code. When an application is choose to initiate a sharing, its App.OnSharingTargetActivated method is called. You can then override it to create a custom control and activate it. Here is a sample example:
[csharp]protected override
void OnSharingTargetActivated(ShareTargetActivatedEventArgs args)
{
var shareTargetPage = new HelloWorld.SharingPage1();
shareTargetPage.Activate(args);
}
[/csharp]

Then in the custom control activation method, you can display it and process the data trough the ShareOperation property (returning a ShareOperation object):
[csharp]
public void Activate(ShareTargetActivatedEventArgs args)
{
if (args.Kind != ActivationKind.ShareTarget) return;
if (!ProcessArgs(args)) return;

// Use the share button to commit the sharing request
ShareButton.Click += (backSender, backArgs) =>
{
// TODO: Perform application-specific work to accept the shared item
Window.Current.Close();
};

Window.Current.Content = this;
Window.Current.Activate();
}
[/csharp]

The data processing is pretty easy too. There is a “Contains” method which can tell the developper if the shared object contains a specific type of data. You only have to provide a format string using the StandardDataFormats class.

Then you can retrieve the data using the exposed methods : GetBitmap, GetStorageItemsAsync, GetText, GetHtml, GetRtf or GetUri.

Here is an exemple which display a provided bitmap in an image control of the sharing UI:
[csharp]private bool ProcessArgs(ShareTargetActivatedEventArgs args)
{
// does it contains an image ?
var data = args.ShareOperation.Data;
bool containsImage = false;
data.Contains(StandardDataFormats.Uri, out containsImage);
if (!containsImage) return false;

//Yes: display it !
var bitmapStream = data.GetBitmap();
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.SetSource(bitmapStream);
image.Source = bitmapImage;
return true;
}[/csharp]

If you try this code, you’ll find out that it is not working because it keeps throwing an exception “Additional information: COM object that has been separated from its underlying RCW cannot be used.” 🙁 Even the build sample does the same thing so I think this will be fixed soon… The quick work-around I found out is to use directly the args objects and do not create reference to any of it’s property…

Freezing the UI is – really – not a good idea, especially in a Metro app so there is also async operation available to retrieve the data. This method is named GetDataAsync and here is an example of it’s use:
[csharp]GetDataOperation dataAsync = data.GetDataAsync(StandardDataFormats.Bitmap);[/csharp]

Reporting

The ShareOperation object exposes some methods which are here to reports the progress of the sharing to the user:

  • ReportCompleted: the sharing is finished succesfully !
  • ReportDataRetrieved: you have finished retrieving the data from the operation. This permits memory optimisation; OPTIONAL
  • ReportError(string value) : an error occured with a message for the user;
  • ReportStarted(): you started the sharing process; OPTIONAL
  • SetProgressText(string value): the sharing is in progress, providint a message for the user; OPTIONAL

Quick links

One more thing (no, there is no iphone announcment :D) : quick links. They are a way to provide bookmarks of “sharing targeted people” currently named as “quick link”. Here is the description of this feature in the share sample of windows 8 :
“When reporting completed, you can optionally add a Quicklink to make it easier for the user to share to a specific person or group that they share with frequently. This saves them from having to select that person or group in your app every time they share to them.”

This quicklink may be provided to the ReportCompleted. It is builded from an icon, a title, the supported files types (why ?), the supported formats (why ?) and an Id.

Here is an example from the share sample:
[csharp]QuickLink quickLinkInfo = new QuickLink
{
Id = "ddd",
Title = "kikou",
SupportedFileTypes = { ".png", ".wma", ".jpg", ".bmp", ".wmv", ".txt",
".mp3", ".mp4", ".gif", ".docx", ".pptx", ".xlsx", ".pdf" },
SupportedDataFormats = { "unicodetext", "uniformResourceLocatorW", "bitmap" }
};

StorageFile iconFile = await Windows.ApplicationModel
.Package.Current.InstalledLocation
.CreateFileAsync("images\\user.png", CreationCollisionOption.OpenIfExists)
as StorageFile;
quickLinkInfo.Thumbnail = StreamReference.CreateFromFile(iconFile);
[/csharp]

Conclusion

This is a great feature which introduce some new way to improve the user experience. It is easy to implement but demands to be aware of some new concepts which have been seen here !

If you want a complete demo you can download the windows 8 sample which is at this adress: http://code.msdn.microsoft.com/windowsapps/Sharing-Content-Target-App-e2689782

Regards,

 

3 Responses

  1. snore stop now

    30/07/2013 13 h 39 min

    Microsoft have seem to finally emerged as a winner with the introduction of Windows 8. Now, with the WinRT applications these seem to provide more than what is actually needed to ensure the better performance. Waiting to read more posts.

Comments are closed.