Setting up Home Assistant in Docker for Windows with Port Forwarding Enabled

I hope that you’ve landed here before spending hours/days trying to find a solution as to why you can’t forward the Home Assistant port in Docker. The solution is frustratingly easy.


The install Home Assistant in docker on Windows instructions are great, with one exception. It explains the required prerequisites to make sure docker has access to a host disk. However, those instructions have outdated instructions to setup the port-forward rules, which ultimately makes it a waste of time.

They share this command (don’t use):

docker run --init -d --name="home-assistant" -e "TZ=America/Los_Angeles" -v //c/Users/[USER]/homeassistant:/config --net=host homeassistant/home-assistant:stable

It installs fine and spins up the container. The docs say to next use netsh and manually add port-forward rules, but it doesn’t work (and you can seriously mess stuff up with netsh).


Instead, you can just tell docker to port forward it for you when you initially create the container by using the -p switch. Since Home Assistant uses port 8123, you use -p 8123:8123 in the command.

Here’s the one-liner that does both the install, and the port forward, at the same time:

docker run -p 8123:8123 --name="home-assistant" -e "TZ=America/Los_Angeles" -v //c/Users/lance/homeassistant:/config homeassistant/home-assistant:stable

After that, you’re ready to go! Open a browser on the host PC and navigate to http://localhost:8123.

Important -p 8123:8123 parameter must be used before --name. Otherwise, it gets used in the container instead of Docker, which results in a broken install because the container doesn’t know what -p is. I wasted two days before discovering this, thanks to help from Alex Sorokoletov and Martin Sundhaug. I owe them some 🍻.

Using Windows IoT, SignalR, Azure Custom Vision and Xamarin Forms to Flush a Toilet

My cat uses the human toilet. However, he doesn’t know how to flush when he’s done. So, I thought, “Why not train a custom trained machine learning model to know when to flush the toilet for him? That way, I can go on vacation without asking friends to stop by.”

That single thought began my trip through some great modern developer tools and tech to build a full solution for the problem. In this post, I’ll walk you through everything and you can explore the code and parts list here

3D Printed case for Raspberry Pi running Windows IoT and Flusher client application. The gray and white item in the background is the toilet valve.

You might have some initial questions like: “Why use AI, why not just use motion detection to flush it?” There are several ways you could use a non-AI approach (like a motion sensor used in public restrooms), but the cat is way too smart and would try to game the system into getting him extra treats. Ultimately, I need a smart/remote way to know there’s a positive hit (ehem, a “”number one” or a “number two”) and to flush only then.

The system has several parts:

Signal R

Since it is the middle of all the other applications, let’s start with the server project. It is a very simple ASP.NET Core application hosting a SignalR Hub. The hub has 6 methods:

public class FlusherHub : Hub
    public async Task SendMessage(string message)
        await Clients.All.SendAsync(ActionNames.ReceiveMessageName, message);

    public async Task SendFlushRequest(string requester)
        await Clients.All.SendAsync(ActionNames.ReceiveFlushRequestName, requester);

    public async Task SendPhotoRequest(string requester)
        await Clients.All.SendAsync(ActionNames.ReceivePhotoRequestName, requester);

    public async Task SendPhotoResult(string message, string imageUrl)
        await Clients.All.SendAsync(ActionNames.ReceivePhotoResultName, message, imageUrl);

    public async Task SendAnalyzeRequest(string requester)
        await Clients.All.SendAsync(ActionNames.ReceiveAnalyzeRequestName, requester);

    public async Task SendAnalyzeResult(string message, string imageUrl)
        await Clients.All.SendAsync(ActionNames.ReceiveAnalyzeResultName, message, imageUrl);

All clients subscribe to the hub, each with different responsibilities, using a reusable SignalR service class. The Windows IoT application is concerned with listening for Flush and Analyze requests, while the Xamarin applications send and listen those requests.

The web application also has an MVC view so I can manually communicate with the IoT client from a web page.

Windows IoT

Now, let’s talk about the component that does all the heavy lifting; the UWP app running on Windows IoT. This app connects to the SignalR hub and listens for commands as well as sends status updates to all the other projects.

I 3D printed a case for the Raspberry Pi 3 so that it was user friendly and self contained. I decided on an amazing model on Thingiverse, check it out here

Here’s a high level rundown on the construction:

The mechanical part is just a simple replacement toilet value (Danco link) that has a convenient cable that the servo can pull:

Digging into each part of the code would make this post too long. You can drill right down to the code here on GitHub. Let me instead explain with some highlights. When the project starts up, it initializes and starts up several services:

// Sets up the Azure Storage connection
await InitializeAzureStorageService();
// Enables the Webcam connected to the Raspberry Pi
await InitializeCameraServiceAsync();
// Setups the GPIO PWM service that allows me to set a specific angle for a servo motor
await InitializeServoServiceAsync();
// connects to the signalR Hub
await InitializeSignalRServiceAsync();
// Initialized the rest of the GPIO Pins (LEDs, button, etc)

Here’s the general workflow:

  1. When an analyze request comes in or a local trigger occurs (i.e. motion), the app will take a photo.
  2. It uploads the photo to Azure Storage blob and creates an URL to the image.
  3. That image URL is then sent to a trained Azure Custom Vision service. The service will return the analyze results to the IoT Client. (or falls back on using Windows ML and an ONYX model on the device to inference).
  4. If there was a high degree of certainty (85%+) of the presence a #1 or #2, the servo will be moved from 0 degrees to 100 degress and stays there for 5 seconds (this flushes the toilet)
  5. The IoT client will send the results, with image, to the SignalR hub.
  6. Extra – In case a human needs to use that guest bathroom, you can press the triangle button in front of the unit to manually flush.

Using the GPIO pins and Windows IoT APIs, the app changes the status lights to let any humans nearby understand the current state of the unit. GPIO is also used for the Flash LED pin and the PWM signal for the servo.

  • Green (ready, awaiting command)
  • Blue (busy, action in progress)
  • Red (exception or other error)

The analyze task logic looks like this:

    private async Task<AnalyzeResult> AnalyzeAsync(bool useOnline = true)
            // Status LED to indicate operation in progress

            var analyzeResult = new AnalyzeResult();

            // Take a photo
            await flusherService.SendMessageAsync("Generating photo...");
            analyzeResult.PhotoResult = await GeneratePhotoAsync(Requester);

            bool poopDetected;

            if (useOnline)
                Log("[INFO] Analyzing photo using Vision API...");
                await flusherService.SendMessageAsync("Analyzing photo using Vision API...");

                // Option 1 - Online Custom Vision service
                poopDetected = await EvaluateImageAsync(analyzeResult.PhotoResult.BlobStorageUrl);
                Log("[INFO] Analyzing photo offline with Windows ML...");

                await flusherService.SendMessageAsync("Analyzing image with Windows ML...");

                // Option 2 - Use offline Windows ML and ONYX
                poopDetected = await EvaluateImageOfflineAsync(analyzeResult.PhotoResult.LocalFilePath);

            analyzeResult.DidOperationComplete = true;
            analyzeResult.IsPositiveResult = poopDetected;
            analyzeResult.Message = poopDetected ? "Poop detected!" : "No detection, flush skipped.";

            // Update status LED

            return analyzeResult;
        catch (Exception ex)

            return new AnalyzeResult
                IsPositiveResult = false,
                DidOperationComplete = false,
                Message = $"Error! Analyze operation did not complete: {ex.Message}"

If there was a positive result, flush the toilet and send an email:

private async void FlusherService_AnalyzeRequested(string requester)
    Log($"[INFO] Analyze Requested by {requester}.");

    await flusherService.SendMessageAsync("Analyzing...");

    var result = await AnalyzeAsync();

    if (result.DidOperationComplete)
        // Inform subscribers of negative/positive result along with photo used for analyzing.
        await flusherService.SendAnalyzeResultAsync(result.Message, result.PhotoResult.BlobStorageUrl);

        // If there was a positive detection, invoke Flush and send email.
        if (result.IsPositiveResult)
            Log("[DETECTION] Poop detected!");

            Log("[INFO] Alerting email subscribers");
            await SendEmailAsync(result.PhotoResult.BlobStorageUrl);
            Log("[DETECTION] No objects detected.");
        // Inform subscribers of error
        await flusherService.SendMessageAsync("Analyze operation did not complete, please try again later. If this continues to happen, check server or IoT implementation..");

Although the Raspberry Pi isn’t going to be connected to a display in normal use, I did build out a diagnostic dashboard as an admin panel. It uses Telerik UI for UWP charts and gauges to show a history of angle changes and current angle, a slider to manually move the servo to any angle, image to see the last photo taken.

There’s one last piece to the puzzle that I haven’t implemented yet. The actual automation of taking the photo so that I don’t need the admin app to start the analyze operation. At the beginning oft this article, I mentioned using a timer or a motion sensor, I will test both approaches in V2. I expect I’ll end up using a sonar sensor like I did for this Netduino project

Azure Storage

This is a simple reusable Azure Storage service class that implements the Azure Storage .NET SDK to connect with a blob container that holds the image files. The images are deleted after a certain period (90 days) so I don’t end up with a huge container and costs.

Azure Custom Vision & Machine Learning

If you’ve never seen azure custom Vision, I recommend checking it out at Not only can you use the REST API, you can also download a Tensorflow or ONXY model for offline, edge inferencing. As with the storage API, I wrote a reusable Custom Vision service class to do the heavy lifting

In order to train the model, I had to take a lot of gross pictures. As of writing this post, I’ve done 4 training iterations with about 6 hours of training time. To spare you the gritty details, here’s a safe-for-work screenshot of the successful #2 detection:

A test of the model with 85% probability for the two items in the toilet bowl.

I don’t share the endpoint details of my REST API in the demo code, but you can try out the ONXY model with Windows Machine Learning (aka WinML) because the ONYX file (flusher.onyx) is in the UWP project’s assets folder here.


Lastly, the admin applications. I decided to use Xamarin.Forms because I could build all three platform apps at the same time. I also prefer to use XAML when I can, this was a natural choice for me.

In a nutshell, this is similar to the Web admin portal. The app connects directly to the SignalR server and listens for messages coming form the IoT client. It can also request a photo, manually flush or request a complete analyze operation.

Here’s a screenshot at runtime to better explain the operations (to keep it work-safe, the images are only from test runs).

Xamarin.Forms on Android. you can request a photo, a toilet flush or a full analyze operation.

Cat Tax

Finally, the moment many of you were waiting for… my cat tax.

The guest bathroom that belongs to the cat and the star of the show.

Custom TypingStarted and TypingEnded Events

You know that little indicator in a chat that shows if someone is currently typing? I am working on a new post (coming soon, link will be here) that uses SignalR to communicate who is currently typing in a chat room along with the messages themselves.

To determine who is typing, I use a timer and the TextChanged event. The timer logic itself is straightforward, in the TextChanged event starts a timer.

  • The first TextChanged event starts a timer.
  • If the TextChanged event fires again before the timer’s Elapsed event, the timer is stopped and restarted.
  • If the Timer’s Elapsed event is fired first, then the user has stopped typing.

This code is a bit tedious to implement over and over again, so why not just build it into the control itself and invoke a custom TypingStarted and TypingEnded event? Enjoy!

public class TimedEntry : Entry, IDisposable
    private readonly System.Timers.Timer timer;

    public TimedChatEntry()
        TextChanged += TimedChatEntry_TextChanged;

        timer = new System.Timers.Timer(1000);
        timer.Elapsed += timer_Elapsed;

    public event EventHandler<EventArgs> TypingStarted;

    public event EventHandler<EventArgs> TypingEnded;

    private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs args)
        if (timer == null)

        Device.BeginInvokeOnMainThread(() => TypingEnded?.Invoke(this, new EventArgs()));

    private void TimedChatEntry_TextChanged(object sender, TextChangedEventArgs e)
        if (timer == null)

        if (!timer.Enabled)
            Device.BeginInvokeOnMainThread(() => TypingStarted?.Invoke(this, new EventArgs()));

    public void Dispose()
        if (timer != null)
            timer.Elapsed -= timer_Elapsed;

Here’s an example that uses a SignalR service:

<TimedEntry TypingStarted="TimedChatEntry_OnTypingStarted"
private async void TimedChatEntry_OnTypingStarted(object sender, EventArgs e)
    if (service != null)
        await service.SendTyperAsync(me.Name, true);

private async void TimedChatEntry_OnTypingEnded(object sender, EventArgs e)
    if (service != null)
        await service.SendTyperAsync(me.Name, false);

You can see the entire thing in action, including the SignalR Hub project, here on GitHub: SignalR Chat Room Demo.

Unblocking .NET DLLs on Mac Catalina

There’s a new headache in town. If you run self-hosted Azure DevOps agent, or .NET Core project, on a Mac running Catalina (v 10.15+) and Microsoft Edge, you will have noticed a new behavior where the OS prevents the .NET assembly from working.

This is because it has been marked with a “quarantine” file attribute when it was downloaded with the browser. It’s a security measure that I’m familiar with on Windows. I would typically remove this attribute by right clicking on the file, select “Properties”, then check “Unblock”:

Unblocking a ZIP file on Windows.

At this point, I suspected I had a good idea of what was happening, I just needed to figure out how to check for and remove it on a Mac. I reached out to the dev community on twitter and asked around. Thanks to Eric Lawrence who pointed me to the Chromium code change that shows it is indeed quarantining the file(s).

After reviewing how to read and remove file attributes, indeed I found a attribute on the tarball archive file that is downloaded from Azure DevOps. Since it contains all the .NET assemblies, we can just unblock the tar.gz file and all contents will unblock as well.


Let’s go back to Azure DevOps Agent Pool page, where you download your agent package (see here if you’ve never done this before).

Click the download button to download the tarball file

Now that the file is in the downloads folder, we can use the xattr command to list the attributes. In my case, I’m checking the downloaded compressed file.

xattr vsts-agent-oxs-x64-2.159.2.tar.gz
You’ll see the attributes listed with the xattr command

Bingo! Notice the attribute? That’s the one causing this headache. Now we can see the attribute name, we can remove it by calling the the xattr command again with -d attributeName fileName parameters .

xattr -d vsts-agent-oxs-x64-2.159.2.tar.gz
You will need to give Terminal permission to access the Downloads folder.

Finally list the attributes again to confirm the quarantine has been removed:

Confirm the attribute was removed

Now you can finish extracting the tarball and setting up the agent (or running your .NET core application).

Preparing apps for Windows X and Surface Duo or Neo Devices.

Preface – This is not Microsoft-provided information, just my guess after digging around the Microsoft.UI.Xaml source code after a conversation on Twitter. This is not coming from any MVP-NDA or other NDA source. I will update this post when official information becomes available.

There is suspiciously missing control from the XAML Gallery app – TwoPaneView. It’s in the WinUI 2.2 release, but there’s no documentation, guidance or examples of it being used (yet). The only thing you’ll find is the API reference, which is automatically generated during the build process.

It didn’t go completely unnoticed, another MVP Fons Sonnemans, did find the control in the preview SDK and wrote this blog post. However, now armed with the knowledge of two-screen devices and Windows X on the horizon, I wanted to dig deeper.

API Support

If you look at the Fon’s demo, it might seem like all the control is good for right now is visual state changes that occur within a single Window. If this is what we’ll use for multi-window-single-instance apps, there needs to be some sort of OS level event that bubles useful information up the API. This iswhere my conjecture begins…

I reviewed the source code of the control and found some interesting code in DisplayRegionHelper::GetRegionInfo()

It appears to check if the display region is WindowingEnvironmentKind::Tiled from calling a WinRT API WindowingEnvironment::GetForCurrentView() . Then, the most interesting part that I think supports multi-screen setups, is regions = winrt::Windows::UI::WindowManagement::DisplayRegion::GetRegionsForCurrentView()

Here’s the snippet with the aforementioned lines highlighted:

 winrt::WindowingEnvironment environment{ nullptr };
            environment = winrt::WindowingEnvironment::GetForCurrentView();
        } catch(...) {}

        // Verify that the window is Tiled
        if (environment)
            if (environment.Kind() == winrt::WindowingEnvironmentKind::Tiled)
                winrt::IVectorView<winrt::Windows::UI::WindowManagement::DisplayRegion> regions = winrt::Windows::UI::WindowManagement::DisplayRegion::GetRegionsForCurrentView();
                info.RegionCount = std::min(regions.Size(), c_maxRegions);

                // More than one region
                if (info.RegionCount == 2)
                    winrt::Rect windowRect = WindowRect();

                    if (windowRect.Width > windowRect.Height)
                        info.Mode = winrt::TwoPaneViewMode::Wide;
                        float width = windowRect.Width / 2;
                        info.Regions[0] = { 0, 0, width, windowRect.Height };
                        info.Regions[1] = { width, 0, width, windowRect.Height };
                        info.Mode = winrt::TwoPaneViewMode::Tall;
                        float height = windowRect.Height / 2;
                        info.Regions[0] = { 0, 0, windowRect.Width, height };
                        info.Regions[1] = { 0, height, windowRect.Width, height };

This is the basis of my theory, I could be way off. If I’m wrong, what’s the worst thing that happened? I was forced to think about my application in a multi-window environment? Win-win!


There are no official demos of this that I could find. However, the same source code also had a UITest! I isolated that UI test in a runnable project, that is what you see a recording of in the tweet embedded above. You can download the project from here

Note: I did not set the InsiderSDK as the Target SDK. If you do have SDK 18990 installed and have a device running insider preview, just change the target in the project properties.

Postmortem – Child node “2” compilation error after updating to 18362 SDK

One of the more frustrating things for me is not being able to debug a problem. After updating my UWP app’s Target SDK to 18362 (Windows 10 1903), I was no longer able to compile. I got a very vague error. that I had to dig out of the msbuild logs:

Child node "2" exited prematurely. Shutting down. 

So I dug into the msbuild logs and found the original error message

Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at Microsoft.Windows.UI.Xaml.Build.Tasks.NativeMethodsHelper.Write(…)
   at Microsoft.Xaml.XBF.XbfGenerator.GenerateXbfFromStreams(…)

Which was ultimately caused by this process exception

System.IO.IOException: Pipe is broken.
   at System.IO.Pipes.PipeStream.WinIOError(Int32 errorCode)
   at System.IO.Pipes.PipeStream.BeginWriteCore(Byte[] buffer, Int32 offset, Int32 count, AsyncCallback callback, Object state)
   at System.IO.Pipes.PipeStream.WriteCore(Byte[] buffer, Int32 offset, Int32 count)
   at System.IO.Pipes.PipeStream.Write(Byte[] buffer, Int32 offset, Int32 count)
   at Microsoft.Build.BackEnd.NodeEndpointOutOfProcBase.RunReadLoop(Stream localReadPipe, Stream localWritePipe, ConcurrentQueue`1 localPacketQueue, AutoResetEvent localPacketAvailable, AutoResetEvent localTerminatePacketPump)

After several hours try trying different things to isolate what was causing the issue, I reached out to the engineering team at Microsoft. They took over and dug deeper, which actually required the WDG group to investigate (big shout out to Alan!).

The problem stems from using a property of a custom base class in XAML. For example, if you have a custom control, for example a Telerik control. You need to have the base class listed in the xmlns of the XAML, even if you aren’t explicitly using it.

To make this simple, let’s use an example. This is the specific scenario that caused my error, but it can happen with any custom control. Look at the code sample below. As you can see on Line 5 the xml namespace is defined as input, and it is used on Line 10 for the RadRangeSlider.

<UserControl xmlns=""
        <input:RadRangeSlider Minimum="0" Maximum="10"/>

Notice the Minimum and Maximum properties, those are actually defined in a base class, not in the RadRangeSlider class… this is what causes the exception in the latest SDK.

This will be fixed in a future UWP SDK release, but for now the workaround is to define the xmlns of the base class, even though you’re not explicitly using it. Here’s the fixed version of that code, notice Line 6.

<UserControl xmlns=""
        <input:RadRangeSlider Minimum="0" Maximum="10"/>

I hope the SEO for this post is good enough to go to the top of your Google/Bing search for the eror and this explanation helps someone who encounters the issue in the future. Happy coding!

Draw Your Own Xamarin Pie Chart dynamically

In this tutorial, I’ll show you how to draw your own pie chart just using lines and a list of data items. The code itself is in C#, but the concept can be used on any platform that has a drawing library and ArcSegments.

You can view the entire solution in this GitHub Gist. Okay, let’s get started!

Setting Up

The first thing you’ll need to understand is how the platform’s drawing library makes arcs. In this code, I’ll be using RadPath from Telerik UI for Xamarin most libraries work the same way. RadPath lets you use a custom Geometry which has RadArcSegment object, which has helpful StartAngle and SweepAngle properties.

Let’s start with the data model, with simple Title and Value properties:

public class ChartDataPoint
    public string Title { get; set; }
    public double Value { get; set; }

Next, let’s create a list that is populated with some activities to represent a 24 hour period.

var dataPoints = new List<ChartDataPoint>
    new ChartDataPoint { Title = "Work", Value = 9 },
    new ChartDataPoint { Title = "Commute", Value = 1.5 },
    new ChartDataPoint { Title = "Leisure", Value = 6 },
    new ChartDataPoint { Title = "Sleep", Value = 7.5 },

Finally, to finish the setup, create a list of colors we can use for the pie slices.

var colors = new List<Color>

Part 1 – Creating the Slices

Now that we have some items, lets move on to generating and drawing the slices. First, we’ll create a container to put the pie and legend into. A Grid is convenient option because we can have two rows, one for the pie and one for the legend.

// Root container to hold the chart and any legend
var container = new Grid();
container.RowDefinitions.Add(new RowDefinition { Height = new GridLength(3, GridUnitType.Star) });
container.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });

Now we can start calulating the slice sizes, to do this, we need a total value to get a percentage of that total. We also need a variable to hold the current position on the 360 degree arc where the slices are rendered.

// Sum up all the values to be displayed
var totalValue = dataPoints.Sum(d => d.Value);

// Variable to keep track of where each slice ended.
double currentPosition = 0;

Now for the guts of the operation. We need iterate over the data points and create the arc segments using the data point’s Value property. The code comments will guide you through what each line does, in a nustshell here’s the lifecycle

  • Calculate the data item’s percentage of the total sum
  • Use that percentage to get what percent of 360 degree pie that slice needs
  • Create the RadArcSegment using the current position for the StartAngle and the angle percentage as the SweepAngle
  • Construct the RadPath using the ArgSegment’s geometry and a color from the colors list
// Iterate over the data points to create slices.
for (int i = 0; i < dataPoints.Count; i++)
    // Determine the what percentage that data item's value is of the whole
    double slicePercentage = dataPoints[i].Value / totalValue;

    // Calculate the sweep angle using that percentage amount.
    double sweep = slicePercentage * 360;

    // Create the ArcSegment using the current position and sweep
    var segment = new RadArcSegment
        Center = new Point(0.5, 0.5),
        Size = new Size(1, 1),
        StartAngle = currentPosition,
        SweepAngle = sweep,

    // Important - Calculate the last segment's ending angle in order to have a valid start angle for the next loop.
    currentPosition = currentPosition + sweep - 360;

    // Prepare the required PathFigure and add the ArcSegment
    var figure = new RadPathFigure { StartPoint = new Point(0.5, 0.5) };

    // Create the PathGeometry and add the PathFigure
    var geometry = new RadPathGeometry();

    // Construct the RadPath
    // - Select a Fill color from the brushes parameter (important: use a modulus to wrap to the beginning)
    // - Use the Geometry created from the value
    var slice = new RadPath
        Fill = new RadSolidColorBrush(colors[i % colors.Count]),
        Geometry = geometry,
        HorizontalOptions = LayoutOptions.Center,
        VerticalOptions = LayoutOptions.Center,
        WidthRequest = 100,
        HeightRequest = 100,
        Margin = new Thickness(0, 20, 0, 0)

    // This isn't necessary, but added for completion.
    Grid.SetRow(slice, 0);

    // Finally, add it to the container.

At this point, you now have a full 360 degree chart, with colored slices for each of the data points representing their percentage of the whole.

Part 2 – Creating the Legend

The next phase of the operation is to create the legend. This needs to create text for each slice, as well as a marker that matches the same color of that slice. This could have been done in the same loop as creating the slice, but having a separate loop lets you decide to use a legend or not.

Again, we iterate over the data points. This time we use the Title property of the data point to create the text. To match the color, we use the same modulus to get index and assign it to a RadBorder that creates a thick bar underneath the text.

// Create a horizontal StackLayout to hold the legend items
var legendPanel = new StackLayout
    Orientation = StackOrientation.Horizontal,
    HorizontalOptions = LayoutOptions.Center,
    VerticalOptions = LayoutOptions.Center,
    Margin = new Thickness(0, 16, 0, 0),
    Spacing = 5

// Iterate over the data points and create a legend item with a matching color
for (int i = 0; i < dataPoints.Count; i++)
    // Use a RadBorder with only a bottom thickness and match the color to the slice
    var legendItem = new RadBorder
        BorderColor = colors[i % colors.Count],
        BorderThickness = new Thickness(0, 0, 0, 2)

    // Create a Label for each data point and use the Title property
    var label = new Label
        Text = dataPoints[i].Title,
        FontSize = 12,
        Margin = new Thickness(0, 0, 0, 2),
        TextColor = Color.DimGray

    legendItem.Content = label;


// Insert the legend panel in the root container's 2nd row.
Grid.SetRow(legendPanel, 1);

The last thing to do is add the entire container to the UI. In this example, I’m just setting the entire page’s content to the container Grid..

this.Content = container;

Wrapping Up

I hope this is useful for those times when you need ultimate control over rendering of a chart. If you need more complex setup, I recommend the RadPieChart itself, which is far more feature complete than drawing a few arcs 🙂

Talk to the View

There are many scenarios where a UI component might not have a Command or bindable property available for certain features that you need to access from the view model. There is a simple, but powerful, thing you can do to allow this and not break MVVM or testing capability, leverage the Interface.


Let’s imagine the scenario where we have a special ListView control that has a HighlightItem method that can only be called with a direct reference to that control. There isn’t a Command or DependencyProperty (aka BindableProperty in Xamarin.Forms) alternative, so it has to be done in the code behind.

To keep this simple, here’s the page XAML…

<Page x:Class="MyPage">
        <MyPageViewModel x:Name="ViewModel" />

    <SpecialListView x:Name="MyListView" />

…and here is the page code behind.

public partial class MyPage : Page
    public MyPage()

        // The only way to use HighlightItem method is in the code-behind

As you can see, the HighlightItem method has to be used in the code behind because it has a reference to ‘MyListView’. However, you need to use it in the view model, like this:

public class MyPageViewModel
    private void PleaseHighlightItemNow()
        // But, you need to highlight the item from view model


One solution for this is to define an interface.

public interface IHighlightableView
    void Highlight(object item);

With this, you can add a property to the view model and invoke the method:

public class MyPageViewModel
    public IHighlightableView View { get; set; }

    private void PleaseHighlightItem()
        // Call the method on the interface!

Now, the interface can be implemented on the page to complete the circle

public partial class MyPage : Page, IHighlightableView
    public MyPage()

        // Assign this page instance to the view model
        ViewModel.View = this;

    private void Highlight(object itemToHighlight)
       // Now you can directly use the UI component's method


This is a simple approach that will work if you don’t want to (or are not allowed to) use an existing MVVM framework’s built-in DependencyInjection and IoC features. Enjoy!

Using PowerShell to Install an SDK in a DevOps Build Pipeline

I have an open source UWP project that relies on the Ad SDK and Engagement SDK to be installed to Visual Studio. This normally isn’t a problem, because you can just run the MSI on your PC (see installation instructions here and here).

I decided to move the project into DevOps so that I get some of that CI/CD goodness to build and publish new releases automatically to the Microsoft Store. However, there was a problem, when trying to build the project in a DevOps build pipeline, you’ll get the following error:

This means that the Hosted VS2017 Agent that DevOps uses to build a UWP project doesn’t have the Extensions SDKs installed. I have two choices to move forward:

  • Use a private Agent (this uses your local PC to build the project via a server connection )
  • Find a way to install the SDK into the Hosted agent

I did try the first option. I set up the Windows Agent on my Surface Book, connected it to DevOps and it works nicely (this is why you see that early successful build early in the first screenshot above). However, it’s not a solution for me because it means my PC has to be always on and network-connected.

My friend, and MVP peer, Oren Novotny mentioned that you can actually use a PowerShell script to download the MSI file and install it to the Hosted VS2017, this was the break I was looking for!

To implement this, I downloaded the MSI files I needed from the Visual Studio Marketplace and put them into an Azure Blob. It provides me with two reliable URLs to download the files in the PowerShell script.

Next, I wrote the very simple script. It has two phases: a download phase and an install phase (with a quiet switch “/q”). Here’s what that looks like:

# Predefined Variables
$adSdkUrl = ""
 $servicesSdkUrl = ""
 $adSdkPath = Join-Path $env:TEMP "MicrosoftAdvertisingSDK.msi"
 $servicesSdkPath = Join-Path $env:TEMP "MicrosoftStoreServicesSDK.msi"

# Download the files to local temp folder
 Write-Output "downloading $adSdkUrl…"
 Invoke-WebRequest -Uri $adSdkUrl -OutFile $adSDKPath
 Write-Output "downloading $servicesSdkUrl…"
 Invoke-WebRequest -Uri $servicesSdkUrl -OutFile $servicesSdkPath

# Install the SDKs (use the "qn" flag to install silently)
 Write-Output "installing $adSdkPath…"
 Start-Process $adSdkPath -ArgumentList "/q" -Wait
 Write-Output "installing $servicesSdkPath…"
 Start-Process $servicesSdkPath -ArgumentList "/q" -Wait

Next, you need to add a Powershell step to your DevOps Build pipeline and paste in the script. Here’s a screenshot to help guide you:

Now, when the build is triggered, it will download and install the missing SDKs before building the project! Here’s the result of that build step in the Hosted agent’s console:

I hope this post finds you as soon as you need help. It took me several days, a dozen different documentation articles (some are hyperlinked above) and my MVP peers to find a good simple solution that didn’t require my PC .

LoginDialog for easy Live SDK OAuth

Almost every developer I speak with agrees that getting a nicely working OAuth flow can be difficult. After much trial and error, I’ve built a UWP ContentDialog that makes this easy and has built-in refresh token support.

Using the LoginDialog

This is very simple to use, when the app launches, instantiate the dialog by passing your Live SDK ClientID and let the LoginDialog do the heavy lifting:

// Pass your app's OAuth ClientId (sometimes called an AppId)
var loginDialog = new LoginDialog("YourAppClientId");

// *** Perform login **** //
// Case 1 - If the user was previously signed in, there is a refresh_token stored and no user-entered credentials are needed.
// Case 2 - If the access token fails, or if it's the first sign-in, the user will see a popup to enter credentials.
await loginDialog.SignInAsync();

    // This will be the access token you can use for API calls.
    var accessToken = loginDialog.Authentication;

    // Make your API calls with the accessToken, for example:
    var user = await apiService.GetUSerProfileAsync(accessToken);

This works just like a MessageDialog, but instead will show a WebView for the user to sign in, or automatically sign them in silently if they were previously logged in.

Get the full source code in this GitHub Gist.

See this tweet for a video of what it looks like when it automatically logs you in and here’s a screenshot what it looks like when the dialog needs to appear:

Dialog Visible

Operational Summary

Explaining OAuth 2.0 is outside the scope of this article, but to summarize there are a couple round trip to the authentication endpoints.

  1. Load the sign-in landing page and the user signs in with their credentials.
  2. In the redirect after successful sign-in, you’ll get an access_token and a refresh_token for that authenticated user.

The access_token is what is used in all of your API calls that verifies the application is operating on the behalf of that user. The access_token expires after a preset amount of time (e.g. 60 minutes), after which time you have to request another access_token.

Here is where the refresh_token comes in handy. You could go back to step #1 above, but this would require the user re-enter their credentials. Instead, you can just use the refresh_token  you already have for the user to get a new access_token without ever interrupting them to show a WebView.

This is what the LoginDialog does for you, when you call SignInAsync() the following happens:

  • Checks to see if there is a refresh_token stored locally. If there isn’t one, show the WebView and have the user sign in for the first time.
  • If there is a refresh_token stored locally, then use that to automatically get a new access_token without showing the dialog

Since this is general OAuth 2.0 workflow, you could probably adapt the dialog to work for other OAuth 2 endpoints by changing the dialog’s _signInUri, _signOutUri and _redirectUrl values.

Wrapping Up

The LoginDialog lets you have the least amount of interruption to the user while quickly getting an access token for your API use.