0 Comments

imageUWP apps support multiple views/windows. Compared to Windows Forms and WPF apps there’s one big difference in UWP: All application views use different threads. This makes it harder to build applications where different views communicate with each other.

In this post we explore couple different ways of multi-window communication.

Creating a new View (Window) in UWP

To create a new view in UWP app one can use CoreApplication.CreateNewView. Here’s the basic code for opening an another view:

            CoreApplicationView newView = CoreApplication.CreateNewView();
            int newViewId = 0;
            await newView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
            {
                Frame frame = new Frame();
                frame.Navigate(typeof(Secondary), null);
                Window.Current.Content = frame;
                // You have to activate the window in order to show it later.
                Window.Current.Activate();

                newViewId = ApplicationView.GetForCurrentView().Id;
            });

            bool viewShown = await ApplicationViewSwitcher.TryShowAsStandaloneAsync(newViewId);

Here’s an example output:

image

There’s a good tutorial about multi view app development at Dev Center: Show multiple views for an app.

Next, let’s look how we can make the views to communicate with each other.

Example app

In our example app we have two views: The main one and a secondary. Secondary view contains a button and when clicked, we want to update the main view.

Main view has method which updates the TextBlock:

 

        public void UpdateMessage(string newMessage)
        {
            this.Message.Text = newMessage;
        }

The problem

As mentioned, all the views have different threads in UWP. As with Windows Forms and WPF, there’s only one thread which can access UI controls. Trying to access them from other threads will cause exceptions.

The first approach to multi view communication in UWP is the direct one: We pass the main view to secondary view and try to update the main view’s TextBox directly using MainPage.UpdateMessage:

Main view is passed to Secondary View:

                frame.Navigate(typeof(Secondary), this);

Secondary view receives the Main view:

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            this.MainPage = (MainPage) e.Parameter;
        }
 

Main view’s UpdateMessage is called directly:

        private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
        {
            this.MainPage.UpdateMessage("Hello from second view");
        }

Here we hit the problem: This throws an exception:

image

First solution to this problem is using CoreDispatcher directly.

First option: Directly using CoreDispatcher

We can use Main View’s CoreDispatcher to get around this problem. The change is done on the UpdateMessage-method:

        public void UpdateMessage(string newMessage)
        {
            this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => this.Message.Text = newMessage);
        }

With this, we get the desired result:

image

Second option: EventAggregator

The first option works but if there is much communication between the views, it can be tedious to manually call CoreDispatcher at every point. Another option is to change the pattern:

Insted of views communicating directly with each other, you add a middle man which handles the communication between views. EventAggregator is a familiar pattern and it fits into this problem nicely: You raise messages from your views and if some other view is interested, it acts on that message.

I’ve posted a gist which contains a source code of a multi-view UWP EventAggregator. You can examine it to get the idea but in production use it’s good to use something like WeakReferences so that EventAggregator knows when to let go of views.

The idea in this pattern is that you create one EventAggregator for each of your views but the EventAggregator contains a static (shared) list of subscribers which are common to all the views. Here’s what we change in our example app:

Main view:

        
    public sealed partial class MainPage : Page, MainPage.ISubscriber
    {
        public MainPage()
        {
            this.InitializeComponent();
            var eventAggregator = new MyEventAggregator();
            eventAggregator.Subscribe(this);
        }

Note that MainPage now implements ISubscriber.

Secondary view:

        
        public Secondary()
        {
            this.InitializeComponent();
            this.EventAggregator = new MyEventAggregator();
        }

Note that there’s no need to pass Main view to Secondary view: Secondary view doesn’t have to know that Main view exists.

Secondary view raises a message:

        private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
        {
            this.EventAggregator.Publish(new Message("hello from second view"));
        }

Main view handles the message:

        public void Handle(Message message)
        {
            this.Message.Text = message.Text;
        }

image

Conclusion

Different view threads in UWP apps can bite you. You can get around the problem using CoreDispatcher. If there’s much communication happening between the views, it can be better to use a middle man (mediator) to handle the cross thread communication. EventAggregator is one example of this kind of a pattern.

0 Comments

image There’s some cases where SemanticZoom in an UWP app provides a nice way of quickly navigating your app’s content. On the other hand SemanticZoom is something which can be hard for your app’s users to find so one should use it sparingly.

I’ve posted one sample app about SemanticZoom to GitHub. It’s a C# / MVVM app which shows how to combine GridView with SemanticZoom. To get the zoomed out view, you can use CTRL+Mousewheel:

image

Get the code from here:

https://github.com/mikoskinen/UWP-SemanticZoom-GridView

To learn more about SemanticZoom, you can visit Microsoft’s documentation.

0 Comments

imageThe first part of our Aurelia & UWP tutorial showed us how to get started. As mentioned in the end of that post, it was easy to get started but when you start using the Aurelia app using desktop, you’ll notice that you can’t navigate backwards.

This second part of our tutorial will show you how to add back button into your app.

The back button in UWP apps

If you’ve built UWP apps using C# & XAML, you’ve quite likely encountered SystemNavigationManager. Through it, you can add the standard backward navigation button into your app:

image

More about this from the MSDN: Navigation history and backwards navigation for UWP apps

The back button in Aurelia UWP app

So if we can use SystemNavigationManager in C#, what can we do in our Aurelia app? We can use the same SystemNavigationManager!

var systemNavigationManager = Windows.UI.Core.SystemNavigationManager.getForCurrentView();

That’s one big nice thing in UWP: You can access the same WinRT classes and methods from Javascript in addition to C# and C++.

To add the back button, add backbutton.js into your app with the following content:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
(function () {
var systemNavigationManager = Windows.UI.Core.SystemNavigationManager.getForCurrentView();
systemNavigationManager.addEventListener("backrequested", handleSystemNavigationEvent.bind(this));
window.onpopstate =function () {
var systemNavigation = Windows.UI.Core.SystemNavigationManager.getForCurrentView();
if (endsWith(window.location.href,"index.html")) {
systemNavigation.appViewBackButtonVisibility = Windows.UI.Core.AppViewBackButtonVisibility.collapsed;
}else {
systemNavigation.appViewBackButtonVisibility = Windows.UI.Core.AppViewBackButtonVisibility.visible;
}
};
})();
function handleSystemNavigationEvent(args) {
args.handled =true;
window.history.back();
}
function endsWith(str, suffix) {
return str.slice(-suffix.length) === suffix;
}

Then reference backbutton.js in index.html:

image

That’s it. You should now see the back button in your app’s title bar when you navigate away from the home page.

image

You can find the full example from GitHub: https://github.com/mikoskinen/aurelia-uwp/

In part three of Aurelia and UWP tutorial we look how to integrate more UWP app features inside your Aurelia app: The goal is to integrate the Aurelia app with Windows 10 and to make it behave like a standard C#/XAML based UWP app.

0 Comments

imageLately we’ve been writing some apps using Aurelia. Aurelia isn’t the only Javascript framework out there but it’s easily the most productive we have encountered. For someone who has been writing XAML/C# apps for the last seven years or so, Aurelia is the first platform which gives us the same kind of a feeling of productivity as the XAML/C#.

Some of the apps we’ve been building have been such that it would be great if we could release them to the Windows Store. Here’s a step-by-step tutorial on how to package the Aurelia app as an UWP app.

Requirements

Before starting, make sure that you have aurelia-cli up and running. For sample app we can use Aurelia’s “official” todo example app. You can get it from GitHub.

1. Create new UWP app

First, let’s create a new UWP app using the “Blank App (Universal Windows)” template:

image

2. Copy the Aurelia app inside the UWP app’s folder

Now get your Aurelia app or the todo-example app and copy its source code inside the UWP app’s root folder. This should override the default index.html and your folder should now look like the following:

image

3. Build Aurelia app

Next step is to build the Aurelia app. If you’ve just copied the example app from GitHub, you must first install its dependencies:

npm install

When you have the dependencies installed, build the app using aurelia-cli:

au build

image

4. Include required files in Visual Studio

Last step is to include the required files using Visual Studio. Select “scripts” folder and “Include in project”:

image

And you’re all set! Just use F5 to run the app:

image

Conclusion

This tutorial showed you how to “port” Aurelia app to an UWP app.

The source code is available from GitHub.

When you start using the app, you’ll quite likely notice a big problem quickly: There’s no back-button. The part 2 of this series shows how you can add the standard back-button, allowing desktop users to navigate back in your Aurelia app.

0 Comments

This post shows how to encrypt and decrypt string in ASP.NET Core.


Encrypt decrypt output

Lately I’ve been working with ASP.NET Core. The .NET Core moves things around a little bit, at least until .NET Standard 2.0 arrives. Here’s some simple code which I’ve been using to encrypt and decrypt a string in ASP.NET Core using a static key.

First, the example console app:

        public static void Main(string[] args)
        {
            var content = "Example test";
            var key = "E546C8DF278CD5931069B522E695D4F2";

            var encrypted = EncryptString(content, key);
            Console.WriteLine(encrypted);

            var decrypted = DecryptString(encrypted, key);
            Console.WriteLine(decrypted);

            Console.ReadLine();
        }

Secondly, the source code for EncryptString and DecryptString:

        public static string EncryptString(string text, string keyString)
        {
            var key = Encoding.UTF8.GetBytes(keyString);

            using (var aesAlg = Aes.Create())
            {
                using (var encryptor = aesAlg.CreateEncryptor(key, aesAlg.IV))
                {
                    using (var msEncrypt = new MemoryStream())
                    {
                        using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                        using (var swEncrypt = new StreamWriter(csEncrypt))
                        {
                            swEncrypt.Write(text);
                        }

                        var iv = aesAlg.IV;

                        var decryptedContent = msEncrypt.ToArray();

                        var result = new byte[iv.Length + decryptedContent.Length];

                        Buffer.BlockCopy(iv, 0, result, 0, iv.Length);
                        Buffer.BlockCopy(decryptedContent, 0, result, iv.Length, decryptedContent.Length);

                        return Convert.ToBase64String(result);
                    }
                }
            }
        }

        public static string DecryptString(string cipherText, string keyString)
        {
            var fullCipher = Convert.FromBase64String(cipherText);

            var iv = new byte[16];
            var cipher = new byte[16];

            Buffer.BlockCopy(fullCipher, 0, iv, 0, iv.Length);
            Buffer.BlockCopy(fullCipher, iv.Length, cipher, 0, iv.Length);
            var key = Encoding.UTF8.GetBytes(keyString);

            using (var aesAlg = Aes.Create())
            {
                using (var decryptor = aesAlg.CreateDecryptor(key, iv))
                {
                    string result;
                    using (var msDecrypt = new MemoryStream(cipher))
                    {
                        using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                        {
                            using (var srDecrypt = new StreamReader(csDecrypt))
                            {
                                result = srDecrypt.ReadToEnd();
                            }
                        }
                    }

                    return result;
                }
            }
        }

image