Charm Up your Metro App (Part III)
The Developer Preview version is here.
Disclaimer : These articles were written with the Developer Preview version. No guarantee it will work on other versions.
Charming Up Metro App (Part I) : Settings pane.
Charming Up Metro App (Part II) : Search Contract.
Charming Up Metro App (Part III) : Share Contract.
Charming Up Metro App (Part IV) : FilePicker Contract.
This time, we’ll discover the Share Contract. I made two simple image share source and share target applications that will serve as example. The sources are at the end.


Let’s start :
Setting up Share Source
Setting up the source is quite easy. Just add:
using Windows.ApplicationModel.DataTransfer;
Then, in your main page constructor (for instance) add :
// _dataTransferManager is a global field of type DataTransferManager _dataTransferManager = DataTransferManager.GetForCurrentView(); _dataTransferManager.DataRequested += new TypedEventHandler<DataTransferManager, DataRequestedEventArgs>(_dataTransferManager_DataRequested);
What you do is get the current DataTransferManager, and register to the DataRequested event. Event that will be launched when you click on the Share Charm.
Note : you can show programmatically the Share Charm using :
DataTransferManager.ShowShareUI();
The DataRequested event hander has two parameters one of type DataTransferManager and another of type DataRequestedEventArgs. It is the later that will particularly interest us. Specially the Request.Data property, which is of type DataPackage. That class is the one that will exchange the data.
To share data, just fill that class instance. Example, to share an URI :
args.Request.Data.Properties.Title = "An URI";
args.Request.Data.Properties.Description = "Simple example with an URI";
args.Request.Data.SetUri(new Uri("http://Buildwindows.com"));
That’s all ! If you have an app that accepts URI, it will get the one we passed.
Setting up Share Target
To set up the Share target, we need to change the application manifest. The easiest way is to add a new Share Contract item to your project. It will add the Share Target declaration in your manifest.

Now, in your manifest, add in the declaration tab the data formats your application accepts :

VS will do some stuffs. Like adding OnSharingTargetActivated in app.xaml.cs. And adding a shareTargetPage. That is where the magic will happen. Open it and go to the Activate method.
This method will be called when you select the app as share target. In this method, you’ll get the data shared (using the ShareTargetActivatedEventArgs parameter) so you can do what your app is supposed to do with it.
The DataPackage we filled in the source app is the args.ShareOperation.Data property. Taking our example again, to get the URI we do :
var uri = args.ShareOperation.Data.GetUri();
For safety, you should check if the DataPackage contains effectively an URI, using the StandardDataFormats :
bool containsURI; _shareoperation.Data.Contains(StandardDataFormats.Uri, out containsURI);
The default sharing page added by VS has a button to click to proceed the share. In there you will accept the shared items and do your stuff, and dismiss the Sharing UI (with, args.ShareOperation.ReportCompleted() for instance)
Now, your app should appears on the Share Charm if it accepts the format shared :

Sharing examples
There are different type of data you can share. I will show example source and target side for all.
URI
Source (DataRequested event handler):
args.Request.Data.SetUri(new Uri("http://www.buildwindows.com"));
Target (Activate method) :
var uri = args.ShareOperation.Data.GetUri();
Text
Source (DataRequested event handler):
args.Request.Data.SetText("Hello World");
Target (Activate method) :
var textstring = args.ShareOperation.Data.GetText();
RTF
Source (DataRequested event handler):
args.Request.Data.SetRtf(rtfstring);
Target (Activate method) :
var rtfstring = args.ShareOperation.Data.GetRtf();
HTML
Source (DataRequested event handler):
args.Request.Data.SetHtml(htmlstring);
Target (Activate method) :
var htmlstring = args.ShareOperation.Data.GetHtml();
Bitmap
Source (DataRequested event handler):
// First get stream for the image var file = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync(filepath); var stream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read); // then set it in the Data Package args.Request.Data.SetBitmap(stream);
Target (Activate method) :
// Get bitmap var b = new BitmapImage(); b.SetSource(args.ShareOperation.Data.GetBitmap());
Storage Items
Storage item is useful then you have to share several bitmaps (like in my demo apps)
Source (DataRequested event handler):
var storagelist = new List<StorageFile>(); var file = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync(filepath); storagelist.Add(file); args.Request.Data.SetStorageItems(storagelist);
Target (Activate method) :
var liste = new List<BitmapImage>();
// Get list
var storageItemsAsync = _shareoperation.Data.GetStorageItemsAsync();
var task = storageItemsAsync.StartAsTask<IReadOnlyList<IStorageItem>>();
task.Wait();
// for each element in item list, get bitmap
foreach (StorageFile storagefile in task.Result)
{
var bi = new BitmapImage();
var streams = storagefile.OpenAsync(Windows.Storage.FileAccessMode.Read).StartAsTask<IRandomAccessStream>();
streams.Wait();
bi.SetSource(streams.Result);
liste.Add(bi);
}
Data
Data use a stream to pass data. You can pass anything, as long as it can be shared through an IRandomAccessStream. You have to pass the type of the data. It is not necessary to use StandardDataFormats, you can use any string there to describe your data type. In my example, I’ll pass a bitmap using Data. In the target, the OS will be smart enough to let me use GetBitmap.
Source (DataRequested event handler):
var file = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync(filepath); var stream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read); args.Request.Data.SetData(StandardDataFormats.Bitmap, stream);
Target (Activate method) :
// Get bitmap var b = new BitmapImage(); b.SetSource(args.ShareOperation.Data.GetBitmap());
Data Provider
It is the same as Data, but in a asynchronous way. In your source DataRequest handler, you just set the different DataProvider you have. Then, when your target application is selected, it will ask for a DataProvider for a certain type. It will then call your DataProvider handler. In this method, you fill the data in the DataPackage. You can have several data providers, one for each data type you share.
Source (DataRequested event handler):
I set DataProviders for two data type :
args.Request.Data.SetDataProvider(StandardDataFormats.Bitmap, ProviderHandlerMethodForBitmap); args.Request.Data.SetDataProvider(StandardDataFormats.Uri, ProviderHandlerMethodForURI);
Example of handler :
public void ProviderHandlerMethodForBitmap(DataPackage sender, DataProviderArgs args)
{
args.Deferral.DataPackage.SetData(StandardDataFormats.Bitmap, _lincolnStream);
args.Deferral.Complete();
}
Target (Activate method) :
Almost same as for synchronous data:
args.ShareOperation.Data.GetDataAsync(StandardDataFormats.Bitmap)
.StartAsTask<IRandomAccessStream>().ContinueWith(
r =>
{
var liste2 = new List<BitmapImage>();
var b2 = new BitmapImage();
b2.SetSource(r.Result);
liste2.Add(b2);
PresidentsListView.ItemsSource = liste2;
Window.Current.Content = this;
Window.Current.Activate();
},TaskScheduler.FromCurrentSynchronizationContext());
Sharing app names
Your source app can have information about the selected target application. Can be used to do stats or whatever.
You just have to subscribe to the TargetApplicationChosen event :
var _dataTransferManager = DataTransferManager.GetForCurrentView(); _dataTransferManager.TargetApplicationChosen +=
new TypedEventHandler<DataTransferManager, TargetApplicationChosenEventArgs>(_dataTransferManager_TargetApplicationChosen);
Then you can have the application name :
void _dataTransferManager_TargetApplicationChosen(DataTransferManager sender, TargetApplicationChosenEventArgs args)
{
var appname = args.ApplicationName;
}
If you want your target app to know source app name, set the source name in the DataRequested handler :
args.Request.Data.Properties.ApplicationName = "ShareSource";
You can have the name in the activate method of the target :
var sourceappname = args.ShareOperation.Data.Properties.ApplicationName;
Conclusion
There is still a lot of things to say about this contract, this is only the basics.
It is at the same time easy and complex. But very promising, can’t wait to see it use at full potential.
Next : FilePicker Contract !
