Tag Archives: Universal Windows Platform

TaskCompletionSource

I’ve had a couple of problems recently, where I’ve had tasks or asynchronous methods and they don’t quote fit into the architecture that I find myself in. I’d come across the TaskCompletionSource before, but hadn’t realised how useful it was. Basically, a TaskCompletionSource allows you to control when a task finishes; and allows you to do so in a synchronous, or asynchronous fashion. What this gives you is precise control over when an awaited task finishes.

UWP

Consider the following code in UWP. Basically, what this does is execute an anonymous function on the UI thread:

await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High, async () => 
{
    await MyAyncFunc();
}
System.Diagnostics.Debug.WriteLine("After MyAsyncFunc");

The problem here is that executing an anonymous async function in the above scenario doesn’t work. However, using the TaskCompletionSource, we can bypass that whole conversation:

TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();

await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High, async () => 
{
    await MyAyncFunc();
    System.Diagnostics.Debug.WriteLine("After MyAsyncFunc");

    tcs.SetResult(true);
});
await tcs.Task;

Now the function will return when the the TaskCompletionSource.SetResult has been called.

Event based

The second scenario where this is useful is where you are trying to use an event based architecture within an async / await scenario. The following example is a little contrived, but it does illustrate the point:

    class Program
    {
        private static Timer _tmr = new Timer();
        private static TaskCompletionSource<bool> _tcs;

        static void Main(string[] args)
        {
            var tmr = StartTimer();

            Console.WriteLine("Before wait...");
            tmr.Wait();

            Console.WriteLine("After wait...");
        }        

        private static async Task StartTimer()
        {            

            _tmr.Interval = 3000;
            _tmr.Elapsed += _tmr_Elapsed;
            _tmr.Start();

            _tcs = new TaskCompletionSource<bool>();
            await _tcs.Task;
        }

        private static void _tmr_Elapsed(object sender, ElapsedEventArgs e)
        {
            _tcs.SetResult(true);
        }
    }

Potentially, a more real world example of this is when you might want to wrap an API in an async/await.

Control over exactly when a task finishes, and the ability to await async void methods

The final scenario where this can be useful is where you either want to await an `async void` method, or where you have a specific part of a method or process that you want to await.

The following code illustrates how to effectively await an async void method:

    class Program
    {        
        private static TaskCompletionSource<bool> _tcs;

        static void Main(string[] args)
        {
            _tcs = new TaskCompletionSource<bool>();
            BackgroundFunction();

            _tcs.Task.Wait();

            Console.WriteLine("Done");
        }        

        private static async void BackgroundFunction()
        {
            for (int i = 1; i <= 10; i++)
            {
                Console.WriteLine($"Processing: {i}");
                await DoStuff();
            }
            _tcs.SetResult(true);
        }

        private static async Task DoStuff()
        {
            await Task.Delay(500);
            
        }

    }

Finally, here is a parallel for loop:

        static void Main(string[] args)
        {
            Parallel.For(1, 3, (i) =>
            {
                BackgroundFunction();
            });

            Console.WriteLine("Done");
        }        

Imagine that BackgroundFunction is performing a long running task where a specific condition needs to return control. There are obviously combinations of functions in the TPL (WaitAll, WhenAll, WhenAny and WhenAll), however, these rely on the whole task, or a set of tasks, completing. Again, the below example is contrived, but it illustrates the granular control over the task that you have.

        static void Main(string[] args)
        {
            _tcs = new TaskCompletionSource<bool>();

            for (int i = 1; i <= 2; i++)
            {
                BackgroundFunction();
            }

            _tcs.Task.Wait();            

            Console.WriteLine("Done");
        }        

        private static async void BackgroundFunction()
        {
            for (int i = 1; i <= 10; i++)
            {
                Console.WriteLine($"Processing: {i}");
                await DoStuff();

                if (i == 7)
                {
                    _tcs.TrySetResult(true);
                    return;                    
                }
            }            
        }

I will re-iterate again, I realise that in the above example, there are better ways to achieve this, and the example is purely for illustration.

Conclusion

Generally speaking, the simplest and most robust code comes from using the task architecture in the way it was designed: that is, use async / await inside a method that returns a Task. I’m not suggesting in this post that the methods I’ve described should replace that; but there are situations where that might not fit.

Aknowledgements

I used the following posts heavily while writing this:

Awaiting the CoreDispatcher
The Nature of TaskCompletionSource
Real life scenarios for using TaskCompletionSource?
Task Parallelism

Share Content in a UWP App

Sharing has changed slightly between Windows 8 and 10, but broadly speaking, the concept is the same. This article is pretty much where I worked most of this out from; however, there were some small pieces missing for my implementation:

Sharing Video Files

My target here was to share an avi file that I’d just created. My first step was to create a Share Helper (most of what is in here is described in the linked article):

    class ShareHelper
    {
        private IStorageItem _storageItem;

        internal bool Share(IStorageItem storageItem)
        {
            if (storageItem == null)
            {
                return false;
            }

            _storageItem = storageItem;

            DataTransferManager dataTransferManager = DataTransferManager.GetForCurrentView();
            dataTransferManager.DataRequested += DataTransferManager_DataRequested;                                  

            DataTransferManager.ShowShareUI();
            return true;
        }

        private void DataTransferManager_DataRequested(DataTransferManager sender, DataRequestedEventArgs args)
        {
            if (_storageItem == null) return;
                        
            DataRequest request = args.Request;                        
            
            List<IStorageItem> storage = new List<IStorageItem>()
            {
                _storageItem
            };
            request.Data.Properties.Title = "Share";
            request.Data.Properties.Description = "Share your movie!";
            request.Data.SetStorageItems(storage);
            
        }
    }

In Detail

The function SetStorageItems accepts an IEnumarable of IStorageItem. In this case I only have one thing to share, so I’ve just created an arbitrary list. The event handling seems a little overly complex for what it is.

Microsoft recommend that you don’t purposely call the ShowShareUI, but there are a number of situations – for example, the share icon in the camera app – that wouldn’t be intuitive any other way (I’m no UX expert, so I’d be happy to be corrected on this). However, the share UI still behaves as though you has swiped in from the right. To be honest, I kind of expected this Windows 8 chrome to be gone for Windows 10, some is clearly still alive and well.

XAML Translations based on the display size in UWP

Having recently released my latest app into the store, I noticed that some of the buttons didn’t fit well on the phone version. I’d already come across translations for the HTML/WinJS version of Windows 8 apps, but not the XAML version, and not Windows 10 UWP.

You can do this in Expression Blend

First, double click the view file:

transuwp1

In the States window, you’ll then have the ability to create a new VisualStateGroup:

transuwp2

Create the required states; here’s mine:

transuwp3

If you click the lightning bolt to the side of the group, you should get the following:

transuwp4

If you create an adaptive trigger as above, you’ll be able to set the minimum width or height for the change. I’ve set the minimum width for desktop form factor to 500.

Back to code

What that produces for you (remember that you can alt-tab between Blend and VS and it should deal with the changes relatively gracefully) is a piece of code along the lines of this, within the XAML view:

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <VisualStateManager.VisualStateGroups>

            <VisualStateGroup x:Name="VisualStateGroup">

                <VisualState x:Name="Normal">
                    <VisualState.StateTriggers>
                        <AdaptiveTrigger MinWindowWidth="500"/>
                    </VisualState.StateTriggers>
                </VisualState>

                <VisualState x:Name="Mobile">
                    <VisualState.StateTriggers>
                        <AdaptiveTrigger MinWindowWidth="320"/>
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Target="tgPlay.(Grid.Column)" Value="0"/>
                        <Setter Target="tgPlay.(Grid.Row)" Value="1"/>
                        <Setter Target="btnCommandCreateVideo.(Grid.Row)" Value="1"/>
                        <Setter Target="btnCommandCreateVideo.(Grid.Column)" Value="1"/>
                        <Setter Target="btnCommandClear.(Grid.Row)" Value="1"/>
                        <Setter Target="btnCommandClear.(Grid.Column)" Value="2"/>
                        <Setter Target="numericUpDown.(Grid.Column)" Value="0"/>
                        <Setter Target="numericUpDown.(Grid.Row)" Value="1"/>
                        <Setter Target="numericUpDown.(Grid.ColumnSpan)" Value="3"/>
                    </VisualState.Setters>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>

There’s a number of points here – the first is that you need to name your controls; that’s how they are referenced. If you use Blend and you don’t do this then blend will give them a name; for example, I didn’t give “numericUpDown” a name. If I had another control of the same type then it would just number them.

The second point is the adaptive trigger. 500 and 320 seem to be the generally accepted divisions between desktop and narrow form factor. This approach worked for my specific requirement, although what Blend produces does require some re-work, otherwise it just ends up as a mess.

Deleting Files in a Storage Folder Using UWP

Just a little helper method that I used in a recent project to delete files, given a particular name, and excluding a provided list of files:

        internal static async Task DeleteTempFiles(ObservableCollection<StorageFile> exceptionFiles, StorageFolder folder, string fileNameStartsWith)
        {
            var files = (await folder.GetFilesAsync())
                .Where(p => p.DisplayName.StartsWith(fileNameStartsWith)
                && !exceptionFiles.Any(e => e.DisplayName == p.DisplayName));            

            foreach(var file in files)
            {
                await file.DeleteAsync(StorageDeleteOption.Default);                
            }
        }

You can call it like this:

	await FileHelper.DeleteTempFiles(Files, KnownFolders.PicturesLibrary, "_tmpFile");

It will delete all files in the Pictures folder starting with _tmpFile, and exclude anything in the Files collection.

InkCanvas

Pointlessly Long Introduction (feel free to skip)

Some time ago, in a previous job, I was asked to add spell checking to a WPF textbox. I did some research as to how to do that, and came to the conclusion that the only way was using MS Word automation. I must have spent a good three or four hours writing code that interrogated Word and performed spell checking. It wasn’t until I got to auto correct that one of my searches threw up a property on the text box: “SpellCheck.IsEnabled”.

(At the time of writing) I recently attended a developer conference, and at it, I was shown a control called InkCanvas! Having recently spent a considerable amount of time trying to use a Canvas for drawing, I felt like I’d just found the SpellCheck.IsEnabled property again.

Using the InkCanvas Control

In comparison to the Canvas, the InkCanvas basically works out of the box. If you use the InkToolbar with it, you’ll get some errors, but they aren’t actually errors; for example:

1>C:\Program Files (x86)\MSBuild\14.0\bin\Microsoft.Common.CurrentVersion.targets(2048,5): warning MSB3781: The SDK “InkToolbarControl, Version=0.3.2” depends on the following SDK(s) “Microsoft.VCLibs, version=14.0”, which have not been added to the project or were not found. Please ensure that you add these dependencies to your project or you may experience runtime issues. You can add dependencies to your project through the Reference Manager.

Here’s the XAML that I used to get it working. Don’t be phased by the fact that x:Bind doesn’t seem to resolve.

            <InkCanvas x:Name="drawInkCanvas">                    
            </InkCanvas>
            <inkTools:InkToolbar TargetInkCanvas="{x:Bind drawInkCanvas}" 
                                PenColor="#FFE61021" 
                                VerticalAlignment="Top" HorizontalAlignment="Right"/>

Enabling Input

I found only one thing that caused confusion, and it took a while to solve. Basically, the above XAML doesn’t allow you to actually draw anything; you need this:

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);

            drawInkCanvas.InkPresenter.InputDeviceTypes =
                Windows.UI.Core.CoreInputDeviceTypes.Mouse |
                Windows.UI.Core.CoreInputDeviceTypes.Pen |
                Windows.UI.Core.CoreInputDeviceTypes.Touch;

        }

Saving the Image

To save what you’ve drawn, you can use something similar to this code:

            if (canvas != null && canvas.InkPresenter.StrokeContainer.GetStrokes().Count > 0)
            {
                if (file != null)
                {
                    using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite))
                    {
                        await canvas.InkPresenter.StrokeContainer.SaveAsync(stream);
                    }
                }
                Clear(canvas);
            }