Building Messages in Blend for Visual Studio

The other day Martin Zikmond tweeted about a messaging sample app he’d built using the Uno Platform, allowing the same app to run on iOS, Android, Windows, MacOS and Web. Whilst the concept was simple enough, the point was that there was almost no platform specific code and yet the app works and looks virtually … Continue reading “Building Messages in Blend for Visual Studio”

The other day Martin Zikmond tweeted about a messaging sample app he’d built using the Uno Platform, allowing the same app to run on iOS, Android, Windows, MacOS and Web. Whilst the concept was simple enough, the point was that there was almost no platform specific code and yet the app works and looks virtually the same on every platform.

Following my previous post where I did a walk through of some of the Blend for Visual Studio features I use, I thought I’d take the challenge to see how much of Martin’s app I could build using the designer in Blend. The good news is that you can get a long way; The bad news is that there are some features, such as ThemeResources, that seem to cause some issues with the designer – we’ll see this towards the end of the post.

New Project

Ok, so this is pretty self explanatory but Blend has a similar New Project experience to what you see in Visual Studio. Start by searching for the type of project you want to build. So that the designer works, we’re going to select a Blank App (Universal Windows). Once we’ve completed the design work we can copy the files across into our Uno project

Note: At the moment there’s no support for Shared Projects, which the default Uno solution is setup to use. If you follow my post on using multi-targeting with Uno you can use the designer if you load the Windows solution filter.

Give your project a name and location you want it saved.

At this point I typically make sure the application runs and that I’ve upgraded various NuGet packages. Next I’m going to copy in a bunch of the code files from Martin’s project that is available on GitHub. This includes the ViewModels, the SampleData and a couple of Assets.

In the code behind for the MainPage (MainPage.xaml.cs) I’ve added a ViewModel property that returns an instance of the MainViewModel. This will be used to provide both runtime and design time data.

Now let’s get to the designer. From the Assets tool window, search for “split” and drag the SplitView onto the design surface. The SplitView has a Pane, the collapsable panel that shows/hides when you tab the burger menu, and a main Content area. In Martin’s app the list of conversations is in the Pane, whilst the Messages for the selected conversation appear in the Content area.

I wanted to reuse the same color resources that Martin has, so I copied the contents of the App.xaml across to my project – It would be awesome if Microsoft could add back support for managing project resources, which was previously a feature of Blend but got lost in the update to the designer a couple of years ago.

Back to the designer and focus on the SplitView. From the Properties tool window locate the PaneBackground property. Select the Color Resources tab (yeh, Editor and Color Resources are a tab, not that it’s very obvious) and select the NavPaneBackgroundColor (this comes from the resources we added to App.xaml). Whilst we’re here, set the BackgroundSource property to HostBackdrop and TintOpacity to 50%. Check out the docs on Acrylic material for more information on using Windows specific brushes. This is one point where Martin has provided a different background for Windows versus the other platforms – check out the source code to see how he’s done this using platform namespaces.

When you launch the app on Windows you can see the effect of setting the Acrylic background on the pane of the splitview (left side of this image).

Next we’re going to set the Padding on the Grid located inside the Pane, which will inset the list of conversations away from the edge. Rather than just setting the Padding, which can be done using the Properties tool window, I’m going to convert this into a reusable resource. Click the square to the right of the property to display the context menu, then select Convert to New Resource.

Give the resource a name and specify where you want the resource to be saved.

In this case I’m going to go ahead and create a new Resource dictionary by clicking the New… button. Since we’ll use this resource dictionary for styles, templates and other resources, I’ve named it accordingly. When you click the Add button, not only does this resource dictionary get added to your project, it is also wired up as a merge dictionary in App.xaml.

Next we’re going to add a ListView to the Pane to display the list of conversations. Again from the Assets window, drag the ListView across onto the Pane in the designer.

Unfortunately there’s no designer support for working with x:Bind. However, you will get intellisense in the XAML editor to let you know what properties are available for binding to.

Despite setting the ItemsSource property, the ListView still remains empty on the designer – as I mentioned, no designer support for x:Bind. However, with the recently introduced design time data everywhere support that’s been added, you can take advantage of regular data binding at design time.

Firstly, we’ll add an instance of the MainViewModel as design time resource. Note that this is the same as adding normal resources, just with the “d:” prefix. However, be aware that setting attributes at design time will override any runtime values whilst in the designer. This normally isn’t an issue but when specifying resources, it will only pick up the design time resources, rather than attempting to combine the resource dictionaries.

<Grid>
    <d:Grid.Resources>
        <MainViewModel x:Key="DesignViewModel" />
    </d:Grid.Resources>

Note that the XAML editor is able to assist with applying namespaces etc. After adding the MainViewModel resource I get a prompt helping me to setup and use the namespace.

Next, set the ItemsSource property on the ListView, again using the design time prefix (i.e. d:ItemsSource=”{Binding Conversations}” ). Now we should start to see items appear in the ListView.

Let’s go ahead and create a data template for determining how each item will appear. Right-click on the ListView and select Edit Additional Templates, Edit Generated Items (ItemTemplate), followed by Create Empty. Give the DataTemplate a name and specify where you want to save it.

Rather than going through each element in the item template, I’m going to add the DataTemplate from Martin’s code. However, even after adding this data template, there’s no items appearing in the ListView. Again, this is because there’s no designer support for x:Bind. Luckily we can do the same trick, this time for each property we want to data bind. in this example we’re using the design time data binding for the Text property on the TextBlock

Ok, so now we’re starting to look good.

However, notice how the time is appearing at different positions for each item in the list. This is because the list item isn’t spanning the full width of the ListView. I’ve never understood why this is the default behaviour but it dates back as long as I can remember. Luckily there’s an easy fix, which is to set the HorizontalContentAlignment on the ListView to Stretch. However, this needs to be done on the ItemContainerStyle for the ListView. Right-click on the ListView, Edit Additional Templates and then this time select Edit Generated Item Container (ItemContainerStyle), followed by Create Empty.

Give the template a name and location for saving.

From the Properties tool window, search for “horizon” and change the HorizontalContentAlignment to Stretch (far right icon).

Now, the list of conversations is looking much better.

In the main Content area, lets start by creating three rows to host the header, messages and input TextBox. Using the mouse, you can draw the grid rows, and then use the designer to define the height for the rows. The first and third row should both be set to Auto, with the second row set to *.

Let’s add the input TextBox at the bottom of the screen. Click on the chevrons on the left edge of the design to expand out the Assets flyout. Search for textbox and double-click on the TextBox to add it to the designer.

Next, right-click on the newly created TextBox and select Layout, Reset All.

Depending on where the TextBox was added, you’ll probably have to set the Grid.Row to 2 in order for it to appear in the third row. Whilst in the Properties tool window, let’s set the CornerRadius to 12 and the Margin to 20 – again, I would typically extract these to resources so they can be reused across the app (similar to CSS classes if you’re more familiar with styling for the web).

At this point I’m going to grab the rest of the XAML for the Content area from Martin’s source code, rather than walking you through adding each of the controls. There was one exception to this – in Martin’s code he has used an ItemTemplateSelector to switch between two different item templates based on whether the message is from the current user or not. I’m going to take a different approach, so I’ve replaced the ItemTemplateSelector with just a single ItemTemplate. The resulting messages list looks like the following, where it’s no longer possible to distinguish who sent which message.

To fix this issue we’re going to use converters that take a bool value and determine what value to return. The first converter returns a HorizontalAlignment, either Left or Right, depending on the input value. I’ve set it to return Stretch if the input value isn’t a bool, effectively making it the default value.

Next we’re going to make use of this converter in the item template. Here we’ve selected the Border element and are about to click the Create Data Binding menu item.

In the Create Data Binding window, we select the IsFrom property, and then at the bottom of the window, select the BoolHorizontalAlignmentConverter.

If you run the app at this point you’ll see that the messages are aligned left and right according to who sent the message but there’s no difference in style. We can do the same process but this time for setting the Style of different elements in the template; this time using a BoolStyleConverter.

The difference with the BoolStyleConverter is that it needs a TrueStyle and FalseStyle to be defined. For example for the Border we can create two styles and then an instance of the BoolStyleConverter.

And the same for the TextBlock style

And then we apply these to the item template.

And voila, we have a similar layout to what Martin had

Ok, so just in conclusion there’s a couple of points:

  • Firstly, in the style for the Border and TextBlock it’s referencing a ThemeResource to set color. This is important so that you get support for light/dark mode. However, it also seems to break the designer support, resulting in no messages appearing on the screen. I think the resolution might be that the Styles themselves have to be defined as ThemeResources.
  • Secondly, you might be asking why I chose to use converters instead of an ItemTemplateSelector. The answer is that there isn’t any right or wrong answer, I just wanted to demonstrate a different way to appear the problem. In some cases the ItemTemplateSelector is preferred, particularly if there are massive differences between the templates. In this case, I would probably go with converters because you have a single ItemTemplate, so any changes you make will affect both From and To messages, without you having to remember to update both templates.

Hopefully you’ve seen how you can take advantage of Blend for Visual Studio to start building cross-platform experiences; start with Windows (UWP) and apply it to iOS, Android, MacOS and Web using the Uno Platform

Microsoft Build 2020: Uno Platform + WinUI = Future of Cross Platform Apps

I’ve been a long time supporter of the work that the team at Uno Platform have been doing. The announcement today of v3.0 of the Uno Platform comes hot on the heals of releases 2.3 and 2.4 that introduced AndroidX and MacOS support. This isn’t just any old announcement, v3 aligns the Uno Platform with … Continue reading “Microsoft Build 2020: Uno Platform + WinUI = Future of Cross Platform Apps”

I’ve been a long time supporter of the work that the team at Uno Platform have been doing. The announcement today of v3.0 of the Uno Platform comes hot on the heals of releases 2.3 and 2.4 that introduced AndroidX and MacOS support. This isn’t just any old announcement, v3 aligns the Uno Platform with the preview of WinUI 3.

At Built to Roam we’ve been building XAML based applications across a variety of technologies: WPF, Silverlight, WinPhone/Win8, UWP. Each iteration of Windows 10, new features were added to UWP but this limited the reach of the application to devices running the latest version of Windows 10. With WinUI 3.0 Microsoft is detaching the XAML platform away from the Windows version – this means that WinUI can iterate faster and bring newer controls and features to developers. In addition, WinUI also brings with it support for Win32 based applications – more on WinUI here.

So, why is it important that Uno Platform supports WinUI 3.0? Well, if you think of WinUI extending UWP to support all Windows 10 devices, then the addition of the Uno Platform takes WinUI across iOS, Android, macOS and Web via WebAssembly #WinUIEverywhere.

For more information, check out the Announcement of Uno Platform 3.0

Creating a Flutter App for Web

I’ve covered this topic previously in my post Create, Build and Publish a Flutter Web App but things have changed a little now as web support has been merged, making it easier to build a single application that runs on iOS, Android and Web. To find out more you can check out the Flutter docs … Continue reading “Creating a Flutter App for Web”

I’ve covered this topic previously in my post Create, Build and Publish a Flutter Web App but things have changed a little now as web support has been merged, making it easier to build a single application that runs on iOS, Android and Web. To find out more you can check out the Flutter docs for web and Building a web application with Flutter. In this post, I’m going to cover my experience and talk a little about the debugging experience in Visual Studio Code.

With the release of Flutter 1.9 I took a read through the announcement from the Google Developer Days in China and I was initially a little thrown because it indicated that Flutter’s web support has been integrated into the main Flutter repository. I assumed this meant that if I upgraded to 1.9 I would be able to immediately create a Flutter app that targets the mobile and web platforms.

Switching Channel

After upgrading to 1.9 and trying to create a new Flutter project, I quickly realised that I had misunderstood the announcement and that I still needed to switch to a different channel in order to get the integrated experience for Flutter web. So I ran the following command

flutter channel master

After switching to the master channel, I ran:

flutter doctor
flutter upgrade
flutter config --enable-web

New Flutter Project With Web

Once you’ve run these methods, the next thing to do is to create a new Flutter project in Visual Studio code. Press Ctrl+Shift+P to bring up the Command Palette, type Flutter and click Flutter: New Project. After your project is created you’ll notice the addition of a web folder.

Launching Flutter for Web

When you go to launch your Flutter app from within Visual Studio Code you’ll need to decide whether to launch on iOS or Andoird, or the newly supported web. In the lower right corner of Visual Studio Code you can see the current debugging target – in this case it’s already set to use Chrome.

If you tap the debugging target you’ll be prompted to pick an alternative debugging target.

After setting the debugging target, if you press F5 your Flutter app will launch on the appropriate device or emulator. Note that since web support is in preview, there’s no step-through debugging support; you can set breakpoints etc, you just can’t step through the code and inspect variables.

Summary

This was just a short post to draw your attention to the need to switch to the master branch in order to try out the Flutter for web support.

Create, Build and Publish a Flutter Web App

Using Flutter for building iOS and Android applications brings with it some advantages over other cross platform solutions such as Xamarin.Forms or React but one of the more interesting developments to keep an eye on is the support for running Flutter apps on the web. In this post we’re going to create a basic Flutter … Continue reading “Create, Build and Publish a Flutter Web App”

Using Flutter for building iOS and Android applications brings with it some advantages over other cross platform solutions such as Xamarin.Forms or React but one of the more interesting developments to keep an eye on is the support for running Flutter apps on the web. In this post we’re going to create a basic Flutter app and show it running locally. We’re then going to publish it out to Azure blob storage (and accessed via the Azure CDN) to demonstrate that a Flutter web app runs purely in the browser and can be hosted on a static endpoint (i.e. no server side code!).

Installation and Setup

Currently support for Flutter on web requires the webdev package but before installing the package it’s important to make sure that you’ve upgraded the Flutter SDK to the latest version. Run the upgrade command either from a command prompt, or from the terminal console within Visual Studio Code.

flutter upgrade

Next, we need to activate the webdev package using the following command

flutter packages pub global activate webdev

Note there are a couple of things that I ran into. I’m running this all on Windows 10, and I was trying to activate the webdev from within Visual Studio Code. I had opened a new window, which meant I didn’t have a Flutter project open. When I ran the above command I saw an error because apparently there was no pubsec.yaml file.

PS C:\> flutter packages pub global activate webdev
 Error: No pubspec.yaml file found.
 This command should be run from the root of your Flutter project.
 Do not run this command from the root of your git clone of Flutter.

After hunting around a bit I found that you can omit “packages” from the command in order for the webdev package to be retrieved and activated (only required to be done once thanks to the global parameter):

flutter pub global activate webdev

This command might take a minute or so to run. On completion, I saw an interesting notice regarding the cache folder for packages:

Installed executable webdev.
 Warning: Pub installs executables into C:\Source\tools\flutter\.pub-cache\bin, which is not on your path.
 You can fix that by adding that directory to your system's "Path" environment variable.
 A web search for "configure windows path" will show you how.
 Activated webdev 2.5.0.

Currently, the only folder that I’ve included in the Path environment variable is the bin folder for where I’d extracted the Flutter SDK (in my case c:\source\tools\flutter\bin). This was the first time I’d seen this warning and it made me wonder what other folders I needed to include. Following the direction of this post, coupled with the above warning I added the following paths to the Path environment variable.

[flutter folder]\bin
[flutter folder]\.pub-cache\bin
[flutter folder]\bin\cache\dart-sdk\bin
%APPDATA%\Pub\Cache\bin

Note: Make sure you restart any command prompt, terminal window and Visual Studio Code after saving the changes to the Path environment variable in order for it to take effect.

At this point you should be good to go ahead and start creating your new Flutter for web project.

Flutter: New Web Project

From the command palette in Visual Studio Code you can select Flutter: New Web Project. This will go ahead and create your new project with a folder structure that will seem familiar if you’ve been building Flutter apps already. What is different is that after creating the project, it opens index.html in the code editor – you can close this as you probably don’t need to mess with this page initially.

You’ll also notice that there are two main.dart files, one in the web folder, and one in the lib folder. If you inspect these individually you’ll notice that the one in the web folder is an entrypoint (you can see main.dart.js being invoked from index.html which is located in the same folder) which initializes the web platform before calling the main() function located in main.dart in the lib folder. Inside the main.dart in the lib folder you’ll see the layout of a very basic “Hello World” Flutter app.

Running Flutter for Web

Of course, the first thing you’ll want to do is to run the Flutter app, which can be done easily in Visual Studio Code by pressing F5. The first time you attempt to run the project you may be prompted to Select Environment. Select Dart & Flutter to proceed.

Unfortunately this then greets me with a dialog saying that there are build errors:

NOTE: If you get build errors on a newly created Flutter web project. Run flutter upgrade from the terminal within Visual Studio Code, or from the command prompt.

After upgrading my Flutter web project, pressing F5 and selecting the environment, builds and runs the project. Your default browser, Chrome in my case, will be launched in order to display your Flutter web project. The first run does take a while, so don’t close Chrome if it just seems to be blocked loading the project the first time.

Publishing a Flutter Web App

It’s all great being able to run the Flutter web project from within Visual Studio Code (or via the command line using webdev serve). However, at some point you’ll want to think about publishing the project to the web. The great thing about a Flutter web app is that the compiler generates JavaScript that runs within the browser to power your app. There’s no server side component required in order to serve your app.

Ok, but where is this JavaScript and how do I know what to copy to my web server? When you get around to publishing your web app, instead of running webdev serve you just need to use the build parameter:

webdev build

This command will generate a build folder, which will include index.html and main.dart.js, along with any other files that your Flutter web app will require in order to run. All you need to do is to copy the contents of the folder to the appropriate folder on your web server.

In my case I didn’t want to spin up a web server, or even a new endpoint in Azure, just for my simple Flutter web app. Instead I decided to copy the necessary files up to a folder in an existing Blob storage account (in fact it’s the very same storage account that serves the images for this blog). In front of this storage account I use an Azure CDN endpoint in order to improve performance and caching of the content. The net result is that any file that’s retrieved from https://blogimages.builttoroam.com is served from the CDN cache, if it exists. If it isn’t already in the CDN cache, it’ll be pulled from https://nicksblog.blob.core.windows.net, which is the underlying blob storage endpoint, added to the CDN cache and then served up. The point I’m making is that the following Flutter web app (it’s not an image – you can click on it to launch it in a separate tab) is being served from a static service, rather than an actual web server.

Summary

Whilst Flutter for web is still in preview, the simplicity of using the Flutter layout engine for building apps for the web will be a game changed for those of us who have hated the prospect of developing using CSS and JS. Hopefully as it gets closer to a final release there will be an ability to have a single project that’s able to build for iOS, Android and Web without having to have separate projects.

Just out of interest, here are a couple of other articles worth reading on Flutter for the web:


NDC – Sydney – October 14-18

Workshop: Building Cross-Platform Apps With Flutter
Presenters: Pooja Bhaumik and myself

Register for NDC Sydney and come learn how to build amazing Flutter apps!!