First Impressions of AKS, Azure’s New Managed Kubernetes Container Service

Programmatic Ponderings

Kubernetes as a Service

On October 24, 2017, less than a month prior to writing this post, Microsoft released the public preview of Managed Kubernetes for Azure Container Service (AKS). According to Microsoft, the goal of AKS is to simplify the deployment, management, and operations of Kubernetes. According to Gabe MonroyPM Lead, Containers @ Microsoft Azure, in a blog post, AKS ‘features an Azure-hosted control plane, automated upgrades, self-healing, easy scaling.’ Monroy goes on to say, ‘with AKS, customers get the benefit of open source Kubernetes without complexity and operational overhead.

Unquestionably, Kubernetes has become the leading Container-as-a-Service (CaaS) choice, at least for now. Along with the release of AKS by Microsoft, there have been other recent announcements, which reinforce Kubernetes dominance. In late September, Rancher Labs announced the release of Rancher 2.0. According to Rancher, Rancher 2.0 would be based…

View original post 2,337 more words

PullToRefreshListView for UWP

Hello there developer who was just asked to incorporate the PullToRefresh behavior into one of your ListViews for the UWP app you are building. And of course you are looking to steal code on the internet. No blaming, I do it all the time. I actually want you to use this.

photo-15-642x322In case you just crawled out of your cave and aren’t really sure what PullToRefresh is here you go.

 

 

After evaluating the few solutions that were available on the internet I realized none of them fulfilled my requirements perfectly so I had to make my own. To be exact I had to steal code and was hoping that after some tweaking and refactoring I might be able to make it work.

After shamelessly stealing great code from  @dotMorten ‘s blog here RefreshBox for Windows Phone 7 as well as some interesting ideas from an otherwise mediocre Microsoft sample here XamlPullToRefresh I ended up with the code below.

Enjoy!

P.S Scroll to the bottom for some interesting details about this solution.


using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Windows.Input;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Media;
namespace PullToRefreshListView
{
/// <summary>
/// Refresh box. Pull down beyond the top limit on the listview to
/// trigger a refresh, similar to iPhone's lists.
/// </summary>
public class PullToRefreshListView : ListView
{
ScrollViewer _elementScrollViewer;
PullToRefreshOuterPanel _pullToRefreshOuterPanel;
PullToRefreshInnerPanel _pullToRefreshInnerPanel;
public PullToRefreshListView()
{
DefaultStyleKey = typeof(PullToRefreshListView);
}
ScrollViewer ElementScrollViewer
{
get { return _elementScrollViewer; }
set
{
if (_elementScrollViewer != null)
{
_elementScrollViewer.ViewChanging -= OnElementScrollViewerViewChanging;
_elementScrollViewer.DirectManipulationStarted -= OnElementScrollViewerManipulationStarted;
}
_elementScrollViewer = value;
if (_elementScrollViewer != null)
{
_elementScrollViewer.ViewChanging += OnElementScrollViewerViewChanging;
_elementScrollViewer.DirectManipulationStarted += OnElementScrollViewerManipulationStarted;
}
}
}
PullToRefreshInnerPanel PullToRefreshInnerPanel
{
get { return _pullToRefreshInnerPanel; }
set
{
if (_pullToRefreshInnerPanel != null)
_pullToRefreshInnerPanel.SizeChanged -= OnPullToRefreshInnerPanelSizeChanged;
_pullToRefreshInnerPanel = value;
if (_pullToRefreshInnerPanel != null)
_pullToRefreshInnerPanel.SizeChanged += OnPullToRefreshInnerPanelSizeChanged;
}
}
PullToRefreshOuterPanel PullToRefreshOuterPanel
{
get { return _pullToRefreshOuterPanel; }
set
{
if (_pullToRefreshOuterPanel != null)
_pullToRefreshOuterPanel.SizeChanged -= OnPullToRefreshOuterPanelSizeChanged;
_pullToRefreshOuterPanel = value;
if (_pullToRefreshOuterPanel != null)
_pullToRefreshOuterPanel.SizeChanged += OnPullToRefreshOuterPanelSizeChanged;
}
}
FrameworkElement PullToRefreshIndicator { get; set; }
/// <summary>
/// Is the scrollviewer currently being pulled?
/// </summary>
public bool IsPulling { get; private set; }
void OnPullToRefreshInnerPanelSizeChanged(object sender, SizeChangedEventArgs e)
{
PullToRefreshIndicator.Width = PullToRefreshInnerPanel.ActualWidth;
// Hide the refresh indicator
ElementScrollViewer.ChangeView(null, PullToRefreshIndicator.Height, null, true);
}
void OnPullToRefreshOuterPanelSizeChanged(object sender, SizeChangedEventArgs e)
{
PullToRefreshInnerPanel.InvalidateMeasure();
}
/// <summary>
/// Called when the scroll position of the scrollviewer has changed.
/// Used to figure out if the user has over-panned the scrollviewer and if so
/// schedule a refresh when the user releases their finger.
/// </summary>
void OnElementScrollViewerViewChanging(object sender, ScrollViewerViewChangingEventArgs e)
{
if (e.NextView.VerticalOffset == 0)
{
IsPulling = true;
ChangeVisualState(true);
}
else
{
IsPulling = false;
ChangeVisualState(true);
}
// check whether the user released their finger when VerticalOffset=0
// and the direction is up.
if (e.IsInertial &&
e.FinalView.VerticalOffset == PullToRefreshIndicator.Height &&
ElementScrollViewer.VerticalOffset == 0)
{
// wait for the manipulation to end before firing the Refresh event.
ElementScrollViewer.DirectManipulationCompleted += OnElementScrollViewerManipulationCompleted;
}
}
/// <summary>
/// Called when a user manipulation has started. Makes the pull indicator visible.
/// </summary>
void OnElementScrollViewerManipulationStarted(object sender, object e)
{
ElementScrollViewer.DirectManipulationStarted -= OnElementScrollViewerManipulationStarted;
// Hide the indicator until the user starts touching the scrollviewer for the first time.
PullToRefreshIndicator.Opacity = 1;
}
/// <summary>
/// Called when the user releases their finger from the screen after having overpanned the scrollviewer
/// </summary>
void OnElementScrollViewerManipulationCompleted(object sender, object args)
{
ElementScrollViewer.DirectManipulationCompleted -= OnElementScrollViewerManipulationCompleted;
OnRefreshed();
}
private void OnRefreshed()
{
ElementScrollViewer.ChangeView(null, 0, null, true);
IsPulling = false;
ChangeVisualState(true);
PullRefresh?.Invoke(this, EventArgs.Empty);
if (PullRefreshCommand?.CanExecute(null) == true)
PullRefreshCommand.Execute(null);
}
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
ElementScrollViewer = GetTemplateChild("ScrollViewer") as ScrollViewer;
PullToRefreshIndicator = GetTemplateChild("PullToRefreshIndicator") as FrameworkElement;
PullToRefreshInnerPanel = GetTemplateChild("InnerPanel") as PullToRefreshInnerPanel;
PullToRefreshOuterPanel = GetTemplateChild("OuterPanel") as PullToRefreshOuterPanel;
ChangeVisualState(false);
}
private void ChangeVisualState(bool useTransitions)
{
if (IsPulling)
{
GoToState(useTransitions, "Pulling");
}
else
{
GoToState(useTransitions, "NotPulling");
}
}
private bool GoToState(bool useTransitions, string stateName)
{
return VisualStateManager.GoToState(this, stateName, useTransitions);
}
/// <summary>
/// Gets or sets the refresh text. Ie "Pull down to refresh".
/// </summary>
public string RefreshText
{
get { return (string)GetValue(RefreshTextProperty); }
set { SetValue(RefreshTextProperty, value); }
}
/// <summary>
/// Identifies the <see cref="RefreshText"/> property
/// </summary>
public static readonly DependencyProperty RefreshTextProperty =
DependencyProperty.Register("RefreshText", typeof(string), typeof(PullToRefreshListView), new PropertyMetadata("Pull down to refresh…"));
/// <summary>
/// Gets or sets the release text. Ie "Release to refresh".
/// </summary>
public string ReleaseText
{
get { return (string)GetValue(ReleaseTextProperty); }
set { SetValue(ReleaseTextProperty, value); }
}
/// <summary>
/// Identifies the <see cref="ReleaseText"/> property
/// </summary>
public static readonly DependencyProperty ReleaseTextProperty =
DependencyProperty.Register("ReleaseText", typeof(string), typeof(PullToRefreshListView), new PropertyMetadata("Release to refresh…"));
/// <summary>
/// Sub text below Release/Refresh text. For example: Updated last: 12:34pm
/// </summary>
public string PullSubtext
{
get { return (string)GetValue(PullSubtextProperty); }
set { SetValue(PullSubtextProperty, value); }
}
/// <summary>
/// Identifies the <see cref="PullSubtext"/> property
/// </summary>
public static readonly DependencyProperty PullSubtextProperty =
DependencyProperty.Register("PullSubtext", typeof(string), typeof(PullToRefreshListView), null);
/// <summary>
/// Identifies the <see cref="PullIndicatorForeground"/> property
/// </summary>
public Brush PullIndicatorForeground
{
get { return (Brush)GetValue(PullIndicatorForegroundProperty); }
set { SetValue(PullIndicatorForegroundProperty, value); }
}
/// <summary>
/// Identifies the <see cref="PullIndicatorForeground"/> property
/// </summary>
public static readonly DependencyProperty PullIndicatorForegroundProperty =
DependencyProperty.Register("PullIndicatorForeground", typeof(Brush), typeof(PullToRefreshListView), null);
/// <summary>
/// Identifies the <see cref="PullRefreshCommand"/> property
/// </summary>
public ICommand PullRefreshCommand
{
get { return (ICommand)GetValue(PullRefreshCommandProperty); }
set { SetValue(PullRefreshCommandProperty, value); }
}
/// <summary>
/// Identifies the <see cref="PullRefreshCommand"/> property
/// </summary>
public static readonly DependencyProperty PullRefreshCommandProperty =
DependencyProperty.Register("PullRefreshCommand", typeof(ICommand), typeof(PullToRefreshListView), null);
/// <summary>
/// Triggered when the user requested a refresh.
/// </summary>
public event EventHandler PullRefresh;
}
/// <summary>
/// The PullToRefreshOuterPanel works together with the <see cref="PullToRefreshInnerPanel"/>
/// to workaround the problem where List Virtualization is disabled when ListView is hosted
/// inside a ScrollViewer.
/// Specifically the InnerPanel is able to report to the ListView as available height the OuterPanel's height
/// instead of infinity which would be the case when a ScrollViewer is hosted inside another ScrollViewer.
/// </summary>
internal class PullToRefreshOuterPanel : Panel
{
public Size AvailableSize { get; private set; }
public Size FinalSize { get; private set; }
protected override Size MeasureOverride(Size availableSize)
{
AvailableSize = availableSize;
// Children[0] is the outer ScrollViewer
this.Children[0].Measure(availableSize);
return this.Children[0].DesiredSize;
}
protected override Size ArrangeOverride(Size finalSize)
{
FinalSize = finalSize;
// Children[0] is the outer ScrollViewer
this.Children[0].Arrange(new Rect(0, 0, finalSize.Width, finalSize.Height));
return finalSize;
}
}
/// <summary>
/// The PullToRefreshOuterPanel works together with the <see cref="PullToRefreshInnerPanel"/>
/// to workaround the problem where List Virtualization is disabled when ListView is hosted
/// inside a ScrollViewer.
/// Specifically the InnerPanel is able to report to the ListView as available height the OuterPanel's height
/// instead of infinity which would be the case when a ScrollViewer is hosted inside another ScrollViewer.
/// </summary>
internal class PullToRefreshInnerPanel : Panel, IScrollSnapPointsInfo
{
EventRegistrationTokenTable<EventHandler<object>> _verticaltable = new EventRegistrationTokenTable<EventHandler<object>>();
EventRegistrationTokenTable<EventHandler<object>> _horizontaltable = new EventRegistrationTokenTable<EventHandler<object>>();
protected override Size MeasureOverride(Size availableSize)
{
// need to get away from infinity
var parent = this.Parent as FrameworkElement;
while (!(parent is PullToRefreshOuterPanel))
{
parent = parent.Parent as FrameworkElement;
}
var pullToRefreshOuterPanel = parent as PullToRefreshOuterPanel;
// Children[0] is the Border that comprises the refresh UI
this.Children[0].Measure(pullToRefreshOuterPanel.AvailableSize);
// Children[1] is the ListView
this.Children[1].Measure(new Size(pullToRefreshOuterPanel.AvailableSize.Width, pullToRefreshOuterPanel.AvailableSize.Height));
return new Size(this.Children[1].DesiredSize.Width, this.Children[0].DesiredSize.Height + pullToRefreshOuterPanel.AvailableSize.Height);
}
protected override Size ArrangeOverride(Size finalSize)
{
// need to get away from infinity
var parent = this.Parent as FrameworkElement;
while (!(parent is PullToRefreshOuterPanel))
{
parent = parent.Parent as FrameworkElement;
}
var pullToRefreshOuterPanel = parent as PullToRefreshOuterPanel;
// Children[0] is the PullToRefreshIndicator
this.Children[0].Arrange(new Rect(0, 0, this.Children[0].DesiredSize.Width, this.Children[0].DesiredSize.Height));
// Children[1] is the ItemsScrollViewer
this.Children[1].Arrange(new Rect(0, this.Children[0].DesiredSize.Height, pullToRefreshOuterPanel.FinalSize.Width, pullToRefreshOuterPanel.FinalSize.Height));
return finalSize;
}
bool IScrollSnapPointsInfo.AreHorizontalSnapPointsRegular => false;
bool IScrollSnapPointsInfo.AreVerticalSnapPointsRegular => false;
IReadOnlyList<float> IScrollSnapPointsInfo.GetIrregularSnapPoints(Orientation orientation, SnapPointsAlignment alignment)
{
if (orientation == Orientation.Vertical)
{
var l = new List<float>();
l.Add((float)this.Children[0].DesiredSize.Height);
return l;
}
else
{
return new List<float>();
}
}
float IScrollSnapPointsInfo.GetRegularSnapPoints(Orientation orientation, SnapPointsAlignment alignment, out float offset)
{
throw new NotImplementedException();
}
event EventHandler<object> IScrollSnapPointsInfo.HorizontalSnapPointsChanged
{
add
{
var table = EventRegistrationTokenTable<EventHandler<object>>
.GetOrCreateEventRegistrationTokenTable(ref this._horizontaltable);
return table.AddEventHandler(value);
}
remove
{
EventRegistrationTokenTable<EventHandler<object>>
.GetOrCreateEventRegistrationTokenTable(ref this._horizontaltable)
.RemoveEventHandler(value);
}
}
event EventHandler<object> IScrollSnapPointsInfo.VerticalSnapPointsChanged
{
add
{
var table = EventRegistrationTokenTable<EventHandler<object>>
.GetOrCreateEventRegistrationTokenTable(ref this._verticaltable);
return table.AddEventHandler(value);
}
remove
{
EventRegistrationTokenTable<EventHandler<object>>
.GetOrCreateEventRegistrationTokenTable(ref this._verticaltable)
.RemoveEventHandler(value);
}
}
}
}


<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
xmlns:controls="using:PullToRefreshListView">
<Style TargetType="controls:PullToRefreshListView">
<Setter Property="IsTabStop"
Value="False" />
<Setter Property="TabNavigation"
Value="Once" />
<Setter Property="IsSwipeEnabled"
Value="True" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility"
Value="Disabled" />
<Setter Property="ScrollViewer.VerticalScrollBarVisibility"
Value="Auto" />
<Setter Property="ScrollViewer.HorizontalScrollMode"
Value="Disabled" />
<Setter Property="ScrollViewer.IsHorizontalRailEnabled"
Value="False" />
<Setter Property="ScrollViewer.VerticalScrollMode"
Value="Enabled" />
<Setter Property="ScrollViewer.IsVerticalRailEnabled"
Value="True" />
<Setter Property="ScrollViewer.ZoomMode"
Value="Disabled" />
<Setter Property="ScrollViewer.IsDeferredScrollingEnabled"
Value="False" />
<Setter Property="ScrollViewer.BringIntoViewOnFocusChange"
Value="True" />
<Setter Property="PullIndicatorForeground"
Value="Gray"/>
<Setter Property="ItemContainerTransitions">
<Setter.Value>
<TransitionCollection>
<AddDeleteThemeTransition />
<ContentThemeTransition />
<ReorderThemeTransition />
<EntranceThemeTransition IsStaggeringEnabled="False" />
</TransitionCollection>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<ItemsStackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:PullToRefreshListView">
<Border BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
BorderThickness="{TemplateBinding BorderThickness}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="PullStates">
<VisualState x:Name="Pulling">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="pulling"
Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="notPulling"
Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation Storyboard.TargetName="rotArrow"
Storyboard.TargetProperty="Angle"
To="0"
Duration="0:0:.25" />
</Storyboard>
</VisualState>
<VisualState x:Name="NotPulling">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="rotArrow"
Storyboard.TargetProperty="Angle"
To="-180"
Duration="0:0:.25" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<controls:PullToRefreshOuterPanel x:Name="OuterPanel"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<ScrollViewer x:Name="ScrollViewer"
TabNavigation="{TemplateBinding TabNavigation}"
HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}"
HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
IsHorizontalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsHorizontalScrollChainingEnabled}"
VerticalScrollMode="Enabled"
VerticalScrollBarVisibility="Hidden"
IsVerticalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsVerticalScrollChainingEnabled}"
IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}"
IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}"
ZoomMode="{TemplateBinding ScrollViewer.ZoomMode}"
IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}"
BringIntoViewOnFocusChange="{TemplateBinding ScrollViewer.BringIntoViewOnFocusChange}"
VerticalSnapPointsType="MandatorySingle"
VerticalSnapPointsAlignment="Near"
AutomationProperties.AccessibilityView="Raw">
<controls:PullToRefreshInnerPanel x:Name="InnerPanel"
VerticalAlignment="Stretch">
<Border x:Name="PullToRefreshIndicator"
Height="60"
HorizontalAlignment="Stretch"
Opacity="0">
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center"
VerticalAlignment="Bottom">
<FontIcon RenderTransformOrigin=".5,.5"
Margin="0,0,4,0"
FontSize="18"
Glyph="&#xE110;"
VerticalAlignment="Center"
Foreground="{TemplateBinding PullIndicatorForeground}"
UseLayoutRounding="False">
<FontIcon.RenderTransform>
<RotateTransform x:Name="rotArrow" />
</FontIcon.RenderTransform>
</FontIcon>
<StackPanel Orientation="Vertical">
<Grid>
<TextBlock Text="{TemplateBinding RefreshText}"
x:Name="notPulling"
FontSize="16"
HorizontalAlignment="Center"
Foreground="{TemplateBinding PullIndicatorForeground}" />
<TextBlock Text="{TemplateBinding ReleaseText}"
Visibility="Collapsed"
x:Name="pulling"
FontSize="16"
HorizontalAlignment="Center"
Foreground="{TemplateBinding PullIndicatorForeground}" />
</Grid>
<TextBlock Text="{TemplateBinding PullSubtext}"
HorizontalAlignment="Center"
Visibility="Collapsed"
FontSize="12"
Foreground="{TemplateBinding PullIndicatorForeground}" />
</StackPanel>
</StackPanel>
</Border>
<ScrollViewer x:Name="ItemsScrollViewer"
VerticalScrollMode="Enabled"
VerticalScrollBarVisibility="Hidden">
<ItemsPresenter Header="{TemplateBinding Header}"
HeaderTemplate="{TemplateBinding HeaderTemplate}"
HeaderTransitions="{TemplateBinding HeaderTransitions}"
Footer="{TemplateBinding Footer}"
FooterTemplate="{TemplateBinding FooterTemplate}"
FooterTransitions="{TemplateBinding FooterTransitions}"
Padding="{TemplateBinding Padding}" />
</ScrollViewer>
</controls:PullToRefreshInnerPanel>
</ScrollViewer>
</controls:PullToRefreshOuterPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

<Geeking>

The first most interesting and important detail of this solution is the trick the Microsoft sample used to bypass the classic problem of putting a ListView inside a ScollViewer which effectively kills Virtualization. Since the PullToRefresh indicator needs to be inside and above the ScrollViewer that hosts the list the same problem applies here. To overcome this
the Microsoft sample used two custom panels (an Inner and Outer) that know each other and can “talk” to each other. The reason virtualization is killed is because when a ListView is hosted inside a ScrollViewer then it thinks it has infinite vertical space because that’s what the ScrollViewer is telling it. The solution above works around this problem by allowing the Inner panel to figure out the Outer panel’s actual visible height and thus correctly calculate it’s own actual visible height which it can get by simply subtracting the size of the PullToRefresh indicator from the Outer panel’s height.
Cool trick.

The second most interesting and important detail was figuring out if the user released their finger when the ScrollViewer was over-stretched.  The limitation of the sample is that the Refresh is scheduled to be triggered once the user overstretches even if the user decides to cancel by slowly unstretching the ScrollViewer back to the original position.
The original attempts to solve this failed because ScrollViewer only exposes the DirectManipulationStarted and DirectManipulationCompleted events and the second one fires too late. Loong after the user has released their finger. The DirectManipulationPointerReleased  event was not available unfortunately.
The trick to solve this turned out to be the use of the ViewChanging event (see line 114) and figuring out the exact moment the user released his/her finger from the screen.
When this occurs at the desired time then :

  1. The event would be Inertial.
  2. The ScrollViewer would be overstretched so VerticalOffset should be zero and
  3. The direction of the inertial movement should be upwards towards the non-stretched state.

This allowed users to change their minds if they didn’t really want to refresh.

</Geeking>

Update: Microsoft has released an updated PullToRefresh  sample that you might also want to evaluate here. There’s also the UWP Community Toolkit here.

Roots and magic behind C# Async/Await explained simply

Are you using C#’s new async/await feature?
It is cool right?
You learned how to use it but you feel like you are missing a piece of the puzzle?
It feels like magic.
You tried digging a little deeper to learn how it works under the hood,
you looked at the IL that the compiler generates, read a bit on the subject but still don’t understand it completely?
Don’t worry. It’s simple really!
Let’s try to distill it to it’s essence.

What if i told you that you could simulate the same feature even before the await keyword was introduced and all
you need from the language is Iterator blocks and lambdas?

The first step is understanding how Iterator blocks work. They are transformed by the compiler into State machines. Head over for a bit to the link above and let @JonSkeet do his magic explaining the details.

Good. Now lets see what smart people came up with (CCR Iterators as far back as 2005) to solve the callback hell that asynchrony produces.

CCR Iterators

Iterators are a C# 2.0 language feature that is used in a novel way by the Concurrency and Coordination Runtime (CCR). Instead of using delegates to nest asynchronous behavior, also known as callbacks, you can write code in a sequential fashion, yielding to CCR arbiters or other CCR tasks. Multi-step asynchronous logic can then be all written in one iterator method, vastly improving readability of the code. At the same time maintaining the asynchronous behavior, and scaling to millions of pending operations since no OS thread is blocked during a yield.

Here’s the simplest interface we can use to describe what Async means to us:

public interface IAsync
{
    void Run(Action continuation);
}

Note that i don’t deal with cancellation, exceptions or results at this point and that’s on purpose.
How can these two be combined to make asynchronous workflows look sequential?
Well, some brilliant guy at some point stood up and said :

What if we called MoveNext() inside the continuation of every Async call?

And that was it 🙂

Here is the AsyncIterator logic :

    public static class Async
    {
        public static void Run(this IEnumerable&amp;lt;IAsync&amp;gt; asyncIterator)
        {
            var enumerator = asyncIterator.GetEnumerator();

            Action recursiveBody = null;
            recursiveBody = delegate
            {
                if (enumerator.MoveNext())
                    enumerator.Current.Run(recursiveBody);
            };

            recursiveBody();
        }

        public static IAsync Create(Action&amp;lt;Action&amp;gt; asyncAction)
        {
            return new AsyncPrimitive(asyncAction);
        }
    }

    public class AsyncPrimitive : IAsync
    {
        private readonly Action&amp;lt;Action&amp;gt; asyncAction;

        public AsyncPrimitive(Action&amp;lt;Action&amp;gt; asyncAction)
        {
            this.asyncAction = asyncAction;
        }

        public void Run(Action continuation)
        {
            asyncAction(continuation);
        }
    }

And here is what our code looks like.

        static void Main(string[] args)
        {
            MyAsyncWorkflow().Run();
        }

        public static IEnumerable&amp;lt;IAsync&amp;gt; MyAsyncWorkflow()
        {
            for (int i = 1; i &amp;lt; 4; i++)
            {
                Log(&amp;quot;Before Async &amp;quot; + i);
                var idx = i;
                yield return Async.Create((moveNext) =&amp;gt; { Log(&amp;quot;Running Async &amp;quot; + idx); moveNext(); });
            }

            Log(&amp;quot;Workflow done!&amp;quot;);
        }

Every time MoveNext() is called the code after the current yield return is called up until the next yield return.
This can happen at any point in time and from any thread because our code is decomposed and transformed into a state machine. At every yield return we give back the asynchronous operation that we want to run and the
AsyncIterator logic takes care of wiring everything up for us.

Here is the output when we run it :

AsyncIteratorRun

How does this relate to C#’s await feature? The IL produced by the compiler is built on this idea.
You can replace in your mind IAsync, IAsync.Run and yield return with Task, Task.ContinueWith and await.
Of course there are a lot more details involved with the full blown C# async/await implementation but the essence is the same.

I hoped this helped you demystify a little bit all the new async/await goodness 🙂

That being said here is how professionals do it 😛 : F# Computation Expressions and F# Asynchronous Workflows

Here are some links for the interested reader :

Stephen Toub’s -> Processing Sequences of Asynchronous Operations with Tasks

Tomas Petricek’s -> Asynchronous Programming in C# using Iterators

Jeffrey Richter’s -> Jeffrey Richter and his AsyncEnumerator

Jon Skeet’s -> Eduasync Series

WP7 vs WP8 Checkbox Style Changes

Hey. I had a small problem yesterday. Minor annoyance to be exact.

What were you trying to do?
Copy paste a WP7 control’s XAML, as is, to be used in a WP8 app.

What happened?
It didn’t work as is. A built-in control’s default style changed in WP8

Really? Which one?
The Checkbox. Well here, see for yourself :

WP7_WP8_Checkbox_Diff

What the what?? How’d that happen?
I think they just changed the controls style. Just like that.
Wait, i have a WinMerge report of the style differences as well here (D/L the html file and open it)

Tip: Open up Blend and click “Edit Template” on the Checkbox to get a copy of its style. Be sure
to do it inside the correct project each time.

Oh i see. How’d that make you feel?
I was a little bummed out..

I was bummed out

Why?
Why? Cause i am lazy and that’s extra work i didn’t want to do.

Relax. It happens. Why would Microsoft do that anyways?
Hell if i know..

Hell if i know

So what are you planning on doing?
Well, I don’t care for the new style. I want to keep the old one. At first i thought I’d make an App-wide StaticResource out of the old style.
Turns out that won’t seem to work easily. Here’s the exception i got by using the old style

CheckBoxStyleException

The new Checkbox doesn’t seem to like it’s old style anymore… Stay tuned for the solution.

-START UPDATE (WITH FIX AND BONUS TOOL) :
The fact that the old style didn’t immediately work on WP8 had to do obviously with a bunch
of missing or changed styles. Well after some dirty work here is the WP7-Like CheckBox Style for WP8 that makes it look like it did on WP7 WP7CheckBoxStyle.xaml.

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Color x:Key="WP7PhoneRadioCheckBoxCheckDisabledColor">#66000000</Color>
    <Color x:Key="WP7PhoneRadioCheckBoxDisabledColor">#66FFFFFF</Color>
    <Color x:Key="WP7PhoneRadioCheckBoxPressedBorderColor">#FFFFFFFF</Color>
    <Color x:Key="WP7PhoneRadioCheckBoxColor">#BFFFFFFF</Color>
    <Color x:Key="WP7PhoneRadioCheckBoxPressedColor">#FFFFFFFF</Color>
    <Color x:Key="WP7PhoneRadioCheckBoxCheckColor">#FF000000</Color>
    <SolidColorBrush x:Key="WP7PhoneRadioCheckBoxBrush" Color="{StaticResource WP7PhoneRadioCheckBoxColor}"/>
    <SolidColorBrush x:Key="WP7PhoneRadioCheckBoxCheckDisabledBrush" Color="{StaticResource WP7PhoneRadioCheckBoxCheckDisabledColor}"/>
    <SolidColorBrush x:Key="WP7PhoneRadioCheckBoxDisabledBrush" Color="{StaticResource WP7PhoneRadioCheckBoxDisabledColor}"/>
    <SolidColorBrush x:Key="WP7PhoneRadioCheckBoxPressedBorderBrush" Color="{StaticResource WP7PhoneRadioCheckBoxPressedBorderColor}"/>
    <SolidColorBrush x:Key="WP7PhoneRadioCheckBoxPressedBrush" Color="{StaticResource WP7PhoneRadioCheckBoxPressedColor}"/>
    <SolidColorBrush x:Key="WP7PhoneRadioCheckBoxCheckBrush" Color="{StaticResource WP7PhoneRadioCheckBoxCheckColor}"/>

    <Style x:Key="WP7PhoneButtonBase" TargetType="ButtonBase">
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="BorderBrush" Value="{StaticResource PhoneForegroundBrush}"/>
        <Setter Property="Foreground" Value="{StaticResource PhoneForegroundBrush}"/>
        <Setter Property="BorderThickness" Value="{StaticResource PhoneBorderThickness}"/>
        <Setter Property="FontFamily" Value="{StaticResource PhoneFontFamilySemiBold}"/>
        <Setter Property="FontSize" Value="{StaticResource PhoneFontSizeMediumLarge}"/>
        <Setter Property="Padding" Value="10,3,10,5"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ButtonBase">
                    <Grid Background="Transparent">
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal"/>
                                <VisualState x:Name="MouseOver"/>
                                <VisualState x:Name="Pressed">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentContainer">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneBackgroundBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ButtonBackground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneForegroundBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="ButtonBackground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneForegroundBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Disabled">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentContainer">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="ButtonBackground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ButtonBackground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="Transparent"/>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <Border x:Name="ButtonBackground" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="0" Margin="{StaticResource PhoneTouchTargetOverhang}">
                            <ContentControl x:Name="ContentContainer" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Foreground="{TemplateBinding Foreground}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
                        </Border>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style x:Key="WP7PhoneRadioButtonCheckBoxBase" BasedOn="{StaticResource WP7PhoneButtonBase}" TargetType="ToggleButton">
        <Setter Property="Background" Value="{StaticResource WP7PhoneRadioCheckBoxBrush}"/>
        <Setter Property="BorderBrush" Value="{StaticResource WP7PhoneRadioCheckBoxBrush}"/>
        <Setter Property="FontSize" Value="{StaticResource PhoneFontSizeMedium}"/>
        <Setter Property="FontFamily" Value="{StaticResource PhoneFontFamilyNormal}"/>
        <Setter Property="HorizontalContentAlignment" Value="Left"/>
        <Setter Property="VerticalContentAlignment" Value="Center"/>
        <Setter Property="Padding" Value="0"/>
    </Style>
    <Style x:Key="WP7CheckBoxStyle" BasedOn="{StaticResource WP7PhoneRadioButtonCheckBoxBase}" TargetType="CheckBox">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="CheckBox">
                    <Grid Background="Transparent">
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal"/>
                                <VisualState x:Name="MouseOver"/>
                                <VisualState x:Name="Pressed">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="CheckBackground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource WP7PhoneRadioCheckBoxPressedBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="CheckBackground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource WP7PhoneRadioCheckBoxPressedBorderBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Fill" Storyboard.TargetName="CheckMark">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource WP7PhoneRadioCheckBoxCheckBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Fill" Storyboard.TargetName="IndeterminateMark">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource WP7PhoneRadioCheckBoxCheckBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Disabled">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="CheckBackground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource WP7PhoneRadioCheckBoxDisabledBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="CheckBackground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Fill" Storyboard.TargetName="CheckMark">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource WP7PhoneRadioCheckBoxCheckDisabledBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Fill" Storyboard.TargetName="IndeterminateMark">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource WP7PhoneRadioCheckBoxCheckDisabledBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentContainer">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                            <VisualStateGroup x:Name="CheckStates">
                                <VisualState x:Name="Checked">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="CheckMark">
                                            <DiscreteObjectKeyFrame KeyTime="0">
                                                <DiscreteObjectKeyFrame.Value>
                                                    <Visibility>Visible</Visibility>
                                                </DiscreteObjectKeyFrame.Value>
                                            </DiscreteObjectKeyFrame>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Unchecked"/>
                                <VisualState x:Name="Indeterminate">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="IndeterminateMark">
                                            <DiscreteObjectKeyFrame KeyTime="0">
                                                <DiscreteObjectKeyFrame.Value>
                                                    <Visibility>Visible</Visibility>
                                                </DiscreteObjectKeyFrame.Value>
                                            </DiscreteObjectKeyFrame>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <Grid Margin="{StaticResource PhoneTouchTargetLargeOverhang}">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="32"/>
                                <ColumnDefinition Width="*"/>
                            </Grid.ColumnDefinitions>
                            <Grid Grid.Column="0">
                                <Border x:Name="CheckBackground" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{StaticResource PhoneBorderThickness}" Background="{TemplateBinding Background}" HorizontalAlignment="Left" Height="32" IsHitTestVisible="False" VerticalAlignment="Center" Width="32"/>
                                <Rectangle x:Name="IndeterminateMark" Fill="{StaticResource WP7PhoneRadioCheckBoxCheckBrush}" HorizontalAlignment="Center" Height="16" IsHitTestVisible="False" Visibility="Collapsed" VerticalAlignment="Center" Width="16"/>
                                <Path x:Name="CheckMark" Data="M0,123 L39,93 L124,164 L256,18 L295,49 L124,240 z" Fill="{StaticResource WP7PhoneRadioCheckBoxCheckBrush}" FlowDirection="LeftToRight" HorizontalAlignment="Center" Height="21" IsHitTestVisible="False" Stretch="Fill" StrokeThickness="3" StrokeLineJoin="Round" Visibility="Collapsed" VerticalAlignment="Center" Width="23"/>
                            </Grid>
                            <ContentControl x:Name="ContentContainer" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Grid.Column="1" Foreground="{TemplateBinding Foreground}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="12,0,0,0" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
                        </Grid>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

Here is a screenshot that shows off 1) how to use the Style and 2) how it actually looks/works:

WP7_WP8_FixedStyle_Vertical
I needed some help for that painful process of finding out what style changed and how between WP7 and WP8 thats why i built a small tool :

WPThemeReviewerTool1 WPThemeReviewerTool2

I call it “WinPhone Theme Reviewer” , it targets WP8 only for now and you can download the source or xapfile.
What i did, essentially, is include MS’s Theme xaml files located “C:\Program Files (x86)\Microsoft SDKs\Windows Phone\vXX\Design\ThemeResources.xaml” for both WP71 and WP8 in the App.

Enjoy 🙂


-END UPDATE


Wait. That probably means even more default styles might be messed up..
know…We’ll just have to wait and see..

Btw. You know you are talking to yourself right?
….

WP7 App on WP8 Breaking Changes – Part 1 – WebRequest’s Referer Changes

Well, after testing a WP7 app running on WP8 guess what happened…It worked differently on WP8.
The issue as described was : Almost all of the thumbnails stopped showing when the user was logged in.

That was an interesting one. It was obvious it was an MS bug (check out the other one I discovered as well here).

Btw let me say that the MS guys have done an amazing job with WP8! They worked really hard to make the deadlines and try to keep that huge promise that all WP7 apps would automagically run as-is on WP8. Huge effort from their part.

Time to relax back and do some bug-hunting 🙂

Thumbnails mean WebRequests. The ones that failed were shown by setting the UriSource on a BitmapImage. We need to go ask the BitmapImage what goes wrong with the requests when running inside a WP8 device. So lets setup fiddler so we can check the traffic. Note that my PC and the WP8 device were connected to the same Wifi network.

Below you can see how to setup the proxy on the phone’s wifi connection (tap on it for settings).

Great. Now I was able to compare the requests made from a WP7 and WP8 device.

Long story short, I was able to pinpoint the issue and it had to do with the fact that

On WP8 MS changed the way they handle/send Referer headers in WebRequests for both  BitmapImage and WebClient

Why my problem occurred : As it turns out the thumbnail requests, once logged in, are authenticated and in that case the server uses the Referer in order to authenticate the request. If the referer is different than the one you used to log in (through a WebClient) the request will fail. So when a WP7 app runs in WP7 device both the BitmapImage and the WebClient send the identical referer (Applications/Installl) but when a WP7 app is running on WP8 then BitmapImage sends a different Referer than what the WebClient sent to the server while authenticating resulting in all thumbnails to fail.

Lets setup a small test case to highlight and visualize the issue.

Here is the test we are going to run :

We are going to try it in 3 scenarios so we can see the results. The scenarios are :

  1. A WP7 app running on WP7
  2. A WP7 app running on WP8
  3. A WP8 app running on WP8

And now here are the results in order :

WP7 app running on WP7

Figure 1 : BitmapImage request (WP7 on WP7)

Figure 2 : WebClient request (WP7 on WP7)

WP7 app running on WP8
WP7AppOnWP8_BitmapImage_Req_PROBLEM

Figure 3 : BitmapImage request (WP7 on WP8) changed!

WP7AppOnWP8_WebClient_Req

Figure 4 : WebClient request (WP7 on WP8) as normal

WP8 app running on WP8
WP8AppOnWP8_BitmapImage_Req

Figure 5 : BitmapImage request (WP8 on WP8)

Figure 6 : WebClient request (WP8 on WP8).

The problem should be really obvious by now.

Concern #1 : I pretty much can’t do anything to workaround this issue. Changing the whole app to manually download all thumbnails is not an option.

Concern #2 : what should we do from now on WP8 for new Apps as far as Referer’s are concerned?

Do we need to use Data/Programs from now on?
Does that mean that for new apps on WP8 we will have to now manually inject the Referer ourselves on all webrequests? And so on…

I have create a forum thread on Microsoft’s WP forums on the issue here

A word of caution on argument validation in Async methods

I have been noticing around in some blogposts and code snippets a pattern being used when validating arguments in Task-returning async methods and that is returning the ArgumentException as part of the Task
instead of immediately failing (directly raising the exception). Something didn’t feel right so i thought i’d try it
out.

Let’s start with defining these 2 async method variations for argument validation :

The first one assigns the exception to the returned Task and the second one immediately raises it the good old-fashioned way.

Next we write our tests that cover the usage scenarios of our async methods :

Both tests try to call our async methods with a null argument by both awaiting and not awaiting them (fire and forget).
And here is what we get after running it :

As expected, we notice that the thrown ,argument validating, exception when assigned to the returning Task and when not awaited by the caller is completely lost! Like it never happened. The Task “swallowed” it.

In most cases this is the expected behavior, when the exception is part of your Task logic and isn’t awaited, but these kind of exceptions should not go unnoticed! They represent usage errors and should be communicated to the caller fast and always. These can be your usual pre-conditions like argument validation, state validation etc.

One of the lessons from this is that you should also be aware of the implications of your async method not being awaited.

I highly recommend reading the “Task-Based Asynchronous Pattern” document from Microsoft here where
it states :

Exceptions

An asynchronous method should only directly raise an exception to be thrown out of the MethodNameAsync call in response to a usage error*. For all other errors, exceptions occurring during the execution of an asynchronous method should be assigned to the returned Task. This is the case even if the asynchronous method happens to complete synchronously before the Task is returned. Typically, a Task will contain at most one exception.  However, for cases where a Task is used to represent multiple operations (e.g. Task.WhenAll), multiple exceptions may be associated with a single Task.

(*Per .NET design guidelines, a usage error is something that can be avoided by changing the code that calls the method. For example, if an error state results when a null is passed as one of the method’s arguments, an error condition usually represented by an ArgumentNullException, the calling code can be modified by the developer to ensure that null is never passed. In other words, the developer can and should ensure that usage errors never occur in production code.)

OrientationHelper for Windows Phone and Windows 8

This is a small utility to help with WP7,WP8 and Windows Store app development where there is a need to design your UX in order to support multiple screen sizes and orientations.
(Phew i almost said Metro Style..Wait..Damn it)

It is inspired by ‘LayoutAwarePage’ , an utility class included in the templates for Windows Store Apps.

On the Windows Phone side there are 6 orientation states:

  • Landscape
  • LandscapeLeft
  • LandscapeRight
  • Portrait
  • PortraitUp
  • PortraitDown

On the Windows Store side there are 4 view states :

  • Filled
  • Snapped
  • FullScreenLandscape
  • FullScreenPortrait

Before we go into details here is an example of the utility working on the Phone in Portrait mode :
On the left side we have setup our utility to automatically run some arbitrary scale animations ,defined in XAML, based on the current Orientation or ViewState. There’s nothing sophisticated in the screenshots below. Simply showing off the functionality.

Here you can see another one automatically running on the left side in Landscape mode.

Similarly on the Windows 8 side:

(FullScreenPortrait)

(FullScreenLandscape)

(Filled)

(Snapped)

What the designer needs to do is describe the UI (Xaml) for all screens and for all possible orientations/view states in order to provide a good UX. There is no clear pattern/guidelines on how this should be done although LayoutAwarePage gives us a good ‘clean’ solution by taking advantage of a well known proven XAML solution called the VisualStateManager. We are, after all, trying to tackle switching between multiple visual states so VisualStateManager sounds like a natural fit. And it is.

The basic idea is , similar to creating Custom Controls, to declare all views for all supported orientations/view states inside the same XAML file (what if the UI is composite though?) and use VisualStates, one for each specific orientation/view state, to describe the UI changes needed to transition between View designs. We will then let VisualStateManager do it’s work by asking it programmatically to switch between states when the platform notifies us of a change in orientation/view state.

What the developer needs to do is manually listen for orientation/view state changes for all visible screens
and call VisualStateManager to transition the current screen to the current view state.

This programmatic part of the developer seems like a lot of manual work that could be done automatically.
There’s gonna be a lot of code-behind spread around listening for the same event and dealing manually
with VisualState changing (or manually enabling/disabling controls, running animations etc etc if we didnt
use VisualStateManager)
Unfortunately no one can help the poor designer (developer?) that has to rewrite/redesign the whole UI
again and again. It has to happen.

LayoutAwarePage solves it by creating a Page base class for Metro style apps.
This utility is instead an attached property and supports Pages, user controls and custom controls. Haven’t made a sample with custom controls but it should be the same as user controls.
What if though i want to create a reusable custom control/user control and i want to have IT define how it should look on different orientations/view states instead of forcing the consumer/user of the control to do it.
Sometimes ,me as a user of a control, might need to tweak more stuff “inside” the control to make it look right. Lets say for example that i have a control that defines two buttons side by side ,stretched, that fill my Landscape view across nicely. I would have liked if the control itself switched them to be stacked (one on top of the other) when in Portrait mode. I can’t do that though unless the control supported that. Note that it would be best if the control supported that but didn’t enforce it.I the user would like to have control over when and if the control is allowed to auto-adapt by itself or i will solve it outside or the control. The utility supports this scenario by letting me decide whether or not to set the attached property OrientationHelper.IsActive on the control that enables it’s orientation/view state support if of course the control has defined the appropriate VisualStates.

The solution seemed transferable to Windows Phone as well and so the utility comes in 3 assemblies supporting WP7/WP8/WIN8.

What we need to do in order to use it is
1) set the attached property OrientationHelper.IsActive=”true” on a Page, UserControl or CustomControl
2) Define one VisualStateGroup on the orientation-aware control named “PageOrientationStates” for WP
and “ApplicationViewStates” for Win8.
3) Define one VisualState for each supported Orientation/ViewState. The VisualState name should match exactly the name of the Orientation/ViewState. For example i would name “Filled” the VisualState that is meant to design my UI when in Filled state.

Setting the attached property :
In this case the UserControl set’s it for demo purposes .It’s overridable.

Defining the VisualStates (For Win8) :

Quick tip : VisualStateGroups and VisualStateManager , i found, work *only* when defined/attached on the
RootElement of your Page or UserControl. Which means it wont work if you declare a control inside a Page, declare VisualStates on it and try to call VSM on that specific control.

Here’s the code for the OrientationHelper.

using System;
using System.Collections.Generic;
using System.Linq;

#if WINDOWS_PHONE
using System.Windows;
using System.Windows.Controls;
using Microsoft.Phone.Controls;
using Orientation = Microsoft.Phone.Controls.PageOrientation;
#else
using Windows.UI.Core;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Orientation = Windows.UI.ViewManagement.ApplicationViewState;
#endif

namespace OrientationHelper
{
    public static class OrientationHelper
    {
#if WINDOWS_PHONE
        private const String VisualStateGroupName = "PageOrientationStates";
#else
        private const String VisualStateGroupName = "ApplicationViewStates";
#endif

        #region IsActive DP

        public static readonly DependencyProperty IsActiveProperty =
            DependencyProperty.RegisterAttached("IsActive", typeof (bool), typeof (OrientationHelper),
                                                new PropertyMetadata(default(bool), OnIsActivePropertyChanged));

        public static void SetIsActive(UIElement element, bool value)
        {
            element.SetValue(IsActiveProperty, value);
        }

        public static bool GetIsActive(UIElement element)
        {
            return (bool) element.GetValue(IsActiveProperty);
        }

        private static void OnIsActivePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var control = d as Control;
            if (control == null)
                return;

            SetupOrientationAwareControl(control, (bool)e.NewValue);

#if WINDOWS_PHONE
            //The control itself can be a page.In every case we need to retry until the containing page is loaded.
            control.Loaded += OnControlLoaded;
#endif

        }

        #endregion

#if WINDOWS_PHONE
        //Note: On the phone side Orientation is Page-specific so we keep the orientation aware controls
        //on the page itself using a Dependency Property
        #region OrientationAwareControls Private DP

        private static readonly DependencyProperty OrientationAwareControlsProperty =
            DependencyProperty.RegisterAttached("OrientationAwareControls", typeof (IList),
                                                typeof (OrientationHelper), null);

        private static void SetOrientationAwareControls(DependencyObject element, IList value)
        {
            element.SetValue(OrientationAwareControlsProperty, value);
        }

        private static IList GetOrientationAwareControls(DependencyObject element)
        {
            return (IList) element.GetValue(OrientationAwareControlsProperty);
        }

        #endregion
#else
        //Note: On the Windows 8 side Orientation is global
        private static IList<WeakReference> orientationAwareControls;
#endif

        private static void SetupOrientationAwareControl(Control control, bool isActive)
        {
#if WINDOWS_PHONE
            var page = FindParentPage(control);
            if (page == null)
                return;
            if (isActive)
            {
                //Add the orientation aware control to the list stored on the Page
                if (GetOrientationAwareControls(page) == null)
                {
                    SetOrientationAwareControls(page, new List());
                    //Start listening for changes
                    page.OrientationChanged += PageOnOrientationChanged;
                }
                if (!GetOrientationAwareControls(page).Contains(control))
                    GetOrientationAwareControls(page).Add(control);
                UpdateOrientationAwareControls(new[] { control }, page.Orientation); //Update this control only

            }
            else
            {
                var orientationAwareControls = GetOrientationAwareControls(page);
                if (orientationAwareControls != null)
                {
                    if (orientationAwareControls.Contains(control))
                    {
                        orientationAwareControls.Remove(control);
                        control.Loaded -= OnControlLoaded;
                    }
                    //Do cleanup for this page if there are no more controls
                    if (!orientationAwareControls.Any())
                    {
                        SetOrientationAwareControls(page, null);
                        page.OrientationChanged -= PageOnOrientationChanged;
                    }
                }
            }
#else
            if (isActive)
            {
                if (orientationAwareControls == null)
                    orientationAwareControls = new List();

                if (!GetOrientationAwareControls().Contains(control))
                {
                    orientationAwareControls.Add(new WeakReference(control));
                    // Note: On the Windows 8 side, probably due to aggressive optimizations,
                    // if the control is not named then when changing orientations/view states any
                    // WeakReference to that control will show it as GCed!
                    // Disclaimer : I ONLY TESTED ON THE SIMULATOR!!
                    if (string.IsNullOrEmpty(control.Name))
                    {
                        control.Name = Guid.NewGuid().ToString();
                    }
                    control.Loaded += OnControlLoaded;

                    if (control.Parent != null)
                    {
                        UpdateOrientationAwareControls(new[] { control }, ApplicationView.Value);
                    }
                }
                if (GetOrientationAwareControls().Any())
                {
                    //TODO: Handle Window changes (Closed)
                    Window.Current.SizeChanged += OnWindowSizeChanged;
                }

            }
            else
            {
                if (GetOrientationAwareControls().Contains(control))
                {
                    var controlWeakRef = orientationAwareControls.Single(weak => control.Equals(weak.Target));
                    orientationAwareControls.Remove(controlWeakRef);
                    control.Loaded -= OnControlLoaded;
                }
                if (!GetOrientationAwareControls().Any())
                {
                    orientationAwareControls = null;
                    Window.Current.SizeChanged -= OnWindowSizeChanged;
                }
            }
#endif
        }

        private static void OnControlLoaded(object sender, RoutedEventArgs routedEventArgs)
        {
            var control = sender as Control;
#if WINDOWS_PHONE
            SetupOrientationAwareControl(control, GetIsActive(control));
#else
            UpdateOrientationAwareControls(new[] { control }, ApplicationView.Value);
#endif
        }

#if WINDOWS_PHONE

        private static PhoneApplicationPage FindParentPage(FrameworkElement el)
        {
            FrameworkElement parent = el;
            while(parent != null)
            {
                if (parent is PhoneApplicationPage)
                    return parent as PhoneApplicationPage;
                parent = parent.Parent as FrameworkElement;
            }
            return null;
        }

        private static void PageOnOrientationChanged(object sender, OrientationChangedEventArgs e)
        {
            var page = sender as PhoneApplicationPage;
            UpdateOrientationAwareControls(GetOrientationAwareControls(page), page.Orientation); //Update all controls
        }
#else
        private static void OnWindowSizeChanged(object sender, WindowSizeChangedEventArgs windowSizeChangedEventArgs)
        {
            UpdateOrientationAwareControls(GetOrientationAwareControls(), ApplicationView.Value);
        }
        private static IEnumerable<Control> GetOrientationAwareControls()
        {
            if(orientationAwareControls == null || !orientationAwareControls.Any())
                return Enumerable.Empty();

            IList<Control> aliveControls = new List<Control>();
            foreach (var controlWeakRef in orientationAwareControls.ToList())
            {
                if (controlWeakRef.IsAlive)
                    aliveControls.Add(controlWeakRef.Target as Control);
                else
                    orientationAwareControls.Remove(controlWeakRef);
            }
            return aliveControls;
        }
#endif

        private static void UpdateOrientationAwareControls(IEnumerable controls, Orientation orientation)
        {
            if (controls == null || !controls.Any())
                return;

            foreach (var control in controls)
            {
                VisualStateManager.GoToState(control, GetVisualStateName(orientation), true);
            }
        }

        private static String GetVisualStateName(Orientation orientation)
        {
            return orientation.ToString();
        }
    }
}

Here’s the whole solution : OrientationHelper.zip

Feel free to comment if you found it useful or found any issue.

Au revoir

A .NET Dev’s baby steps trying to share native code between Win8 and WP8

This is a walkthrough of what i had to do to setup native code sharing between Windows 8 and Windows Phone 8 (using the leaked WP8 SDK). My knowledge of the native world is quite limited and there might be other better ways of doing it. Feel free to comment if you know more about the subject and help out this poor .NET dev 🙂

First we create our Native C++ WinRT Component :

Add New Windows Runtime Component Project

Then we create our Native C++ Phone Runtime Component :

Next we delete from both projects the autogenerated files. From the WinRT project delete the files named Class1.cpp and Class1.h and from the PhoneRT project delete the files named NativeSharedPhoneRT.cpp and NativeSharedPhoneRT.h.

What we need next is a simple class that we will want to share between the two projects. Lets call it MySharedClass. We will create it only on the WinRT side and we will link to it from the PhoneRT side.

I am expecting that i can use preprocessor flags in the same manner that we used to do between Silvelight/WPF and Windows Phone. So the next question is “how do i define my preprocessor directives in C++ projects”?
These simple steps worked for me :

  1. Open the properties of the NativeSharedWinRT project and go to “Configuration Properties -> C/C++ -> Command Line
  2. Enter “/D “_WinRT”” (without the outside quotes) in  “Additional Options” and click Apply.

Screenshot below :

(Note: the only reason i named the directive with an underscore is because the debug directive in one of the templates was named _DEBUG.Thought it might be a convention or something)
As jalfdjalf pointed out directives starting with underscores are reserved (makes sense) so its OK to name our own as we wish (i.e PhoneRT, WinRT).Btw i used PhoneRT instead of the more “official” WinPRT for the phone because its a lot more distinguishable from WinRT.

Do the same thing for the NativeSharedPhoneRT project but add this “/D “_PhoneRT””  instead in the Additonal Options.
Great. Now we have setup our preprocessor directives for both our shared projects. Time to create the shared class. Go to the NativeSharedWinRT project and add an empty MySharedClass.cpp file and an empty MySharedClass.h file. Then go to the NativeSharedPhoneRT project, click “Add existing item” and navigate inside the NativeSharedWinRT folder to locate the newly created files and select those. These files are now linked and the project structure should look like this :

(Note: I tried linking the pch.cpp and pch.h files as well but VS and the compiler didnt like that for
some reason so i kept them unlinked in order to move one)

Ok so far. Now lets add code to our shared class and see how we can start sharing.
Below is only a screenshot of what the code inside our files should be but you will be able to
download the source code and copy paste directly (see download link at end of post).

Notice how opening the header file from inside the WinRT project that the _WinRT directive is active but not the _PhoneRT one just as we wanted. SharedMethodAsync is a WinRT-Style asynchronous method exposed to both WinRT and PhoneRT.

I had planned to also show off how projections worked in the WinRT world but i couldn’t get it to work easily.The plan was to expose a WinRT type like IMap or IIterable and see how they show up projected in C#.

Here is our .cpp file (opened from inside the NativeSharedPhoneRT project) :

Now its time to create our C# clients (one for WinRT and one for PhoneRT) that will consume our shared native libraries.
First is the WinRT C# Client :

Once created click “Add Reference” on it and select the NativeSharedWinRT project.

Big pause here! Can you say “where’s my P/Invoke dude?”  🙂
Now that’s what i call seamless.
Small note.Never forget that the interop cost is ALWAYS there when going back and forth from native <-> managed.Keep in mind that usually there is an interop cost when going native <-> managed and
that applies to WinRT as well although Microsoft has done a lot of work to minimize it.

Then is our PhoneRT C# Client :

Once created click “Add Reference” on it and select the NativeSharedPhoneRT project.

This is how the project structure should look now :

Finally lets see what the code looks like from both client projects.
This is what we get from the Phone Client :

and here is what we get from the Win8 Client :

And that’s it! That was certainly fun 🙂

Source code for this post is here

Solving MvvmLight’s EventToCommand Memory Leak (WP7)

By using MvvmLight‘s EventToCommand you are going to leak serious memory.
Controls and whole Pages you navigate to will never be garbage collected.
Won’t be so “Light” after all if your not carefull.

Some links on the issue here and here.

First let’s try to get a good understanding on why and how this happens and then we will solve it ourselves!

All the code included below for your pleasure 😉

Lets analyze the resulting object reference graph and visualize the leak.

Your ViewModel keeps a reference to a Command.

  • ViewModel -> Command

EventToCommand hooks onto CanExecuteChanged of the Command and therefore EventToCommand will stay alive as long as the Command stays alive.

  • Command -> EventToCommand

EventToCommand is a TriggerAction which means it keeps a reference to the element it has attached on (AssociatedObject property).

  • EventToCommand -> FrameworkElement

UIElements in the visual tree keep a reference to their parent which recursively means they hold on to the Page.

  • FrameworkElement -> Page

So we have this reference chain : ViewModel -> Command -> EventToCommand -> FrameworkElement -> Page

So every Page will live in memory as long as all ViewModels referenced by EventToCommands inside it stay alive.Now its commonplace for ViewModels to stay alive for a long time through an IoC or even being statically declared in App.xaml and so there we go.We found it!
Sounds easy and obvious now but it wasn’t so easy to locate.It took plenty of time fiddling around with the Windows Phone Performance Analysis Tool.Excellent tool.Could be better.Huge improvement compared to WinDbg 🙂

Ok so lets solve it.Whats the weakest link in that chain?

You guessed it its the CanExecuteChanged event.
The command does not need to reference EventToCommand.
This is where WeakEventListener comes in.Its not the purpose of this post to explain how WeakEvents and listeners work so go ahead and do some reading on the net to get you acquainted.

We know EventToCommand adds and removes an EventHandler to/from Command.CanExecuteChanged.
What would be perfect is if EventToCommand itself added a WeakEventListener to the Command and solve this thing for us.
UPDATE: Apparently MvvmLight is maybe trying to “solve” this issue in the next release but in a way that
totally doesn’t make sense to me.By using WeakActions inside of RelayCommand.I have opened a discussion on the issue here with detail explanation.

For those interested here’s one way of solving it inside EventToCommand that i found just playing around (without a lot of design and classes) :

//Need this instance field in order to unhook the correct handler
private EventHandler hSafeCanExecuteChanged = null;
private static void OnCommandChanged(EventToCommand element, DependencyPropertyChangedEventArgs e)
{
	//Effectively the idea here is that instead of implicitly "closure-ing" this (meaning EventToCommand)
	//inside of the EventHandler we don't access anything from the surrounding environment and instead
        //pass this as a WeakReference thus allowing us to be GCed.
	if (element != null)
	{
		if (e.OldValue != null)
		{
			((ICommand)e.OldValue).CanExecuteChanged -= element.hSafeCanExecuteChanged;
			element.hSafeCanExecuteChanged = null;
		}
		ICommand newValue = (ICommand)e.NewValue;
		if (newValue != null)
		{
			var weakElement = new WeakReference(element);
			element.hSafeCanExecuteChanged =
				(o, args) =>
				{
					var evtToCommand = weakElement.Target as EventToCommand;
					if (evtToCommand != null)
						evtToCommand.OnCommandCanExecuteChanged(args);
				};
			newValue.CanExecuteChanged += element.hSafeCanExecuteChanged;
		}
		element.EnableDisableElement();
	}
}

UPDATE: Here is the whole EventToCommand with the fix:

public class EventToCommand : TriggerAction<FrameworkElement>
{
	#region Command Dependency Property

	public ICommand Command
	{
		get { return (ICommand)GetValue(CommandProperty); }
		set { SetValue(CommandProperty, value); }
	}

	public static readonly DependencyProperty CommandProperty =
		DependencyProperty.Register("Command",
									typeof(ICommand),
									typeof(EventToCommand),
									new PropertyMetadata(null, OnCommandPropertyChanged));

	private static void OnCommandPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
	{
		var instance = d as EventToCommand;
		if (instance != null)
			instance.OnCommandChanged((ICommand)e.OldValue, (ICommand)e.NewValue);
	}

	#endregion Command Dependency Property

	#region CommandParameter Dependency Property

	public object CommandParameter
	{
		get { return (object)GetValue(CommandParameterProperty); }
		set { SetValue(CommandParameterProperty, value); }
	}

	public static readonly DependencyProperty CommandParameterProperty =
		DependencyProperty.Register("CommandParameter",
									typeof(object),
									typeof(EventToCommand),
									new PropertyMetadata(null, OnCommandParameterPropertyChanged));

	private static void OnCommandParameterPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
	{
		var instance = d as EventToCommand;
		if (instance != null && instance.AssociatedObject != null)
			instance.EnableDisableElement();
	}

	#endregion CommandParameter Dependency Property

	#region MustToggleIsEnabled Dependency Property

	public bool MustToggleIsEnabled
	{
		get { return (bool)GetValue(MustToggleIsEnabledProperty); }
		set { SetValue(MustToggleIsEnabledProperty, value); }
	}

	public static readonly DependencyProperty MustToggleIsEnabledProperty =
		DependencyProperty.Register("MustToggleIsEnabled",
									typeof(bool),
									typeof(EventToCommand),
									new PropertyMetadata(OnMustToggleIsEnabledPropertyChanged));

	private static void OnMustToggleIsEnabledPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
	{
		var instance = d as EventToCommand;
		if (instance != null && instance.AssociatedObject != null)
			instance.EnableDisableElement();
	}

	#endregion MustToggleIsEnabled Dependency Property

	#region Public
	public bool PassEventArgsToCommand { get; set; }

	public object CommandParameterValue
	{
		get
		{
			return (this._commandParameterValue ?? this.CommandParameter);
		}
		set
		{
			this._commandParameterValue = value;
			this.EnableDisableElement();
		}
	}
	public void Invoke()
	{
		this.Invoke(null);
	}
	#endregion

	private object _commandParameterValue;
	private WeakEventListener<EventToCommand, Object, EventArgs> weakCanExecuteChangedListener;

	protected void OnCommandChanged(ICommand oldCommand, ICommand newCommand)
	{
		if (oldCommand != null)
		{
			weakCanExecuteChangedListener.Detach();
			weakCanExecuteChangedListener = null;
		}
		if (newCommand != null)
		{
			weakCanExecuteChangedListener = new WeakEventListener<EventToCommand, object, EventArgs>(this);
			weakCanExecuteChangedListener.OnEventAction =
				(me, sender, args) =>
				{
					me.EnableDisableElement();
				};
			weakCanExecuteChangedListener.OnDetachAction =
				(weakListener) =>
				{
					newCommand.CanExecuteChanged -= weakListener.OnEvent;
				};
			newCommand.CanExecuteChanged += weakCanExecuteChangedListener.OnEvent;
		}
		this.EnableDisableElement();
	}

	protected override void Invoke(object parameter)
	{
		if (!this.AssociatedElementIsDisabled())
		{
			ICommand command = this.GetCommand();
			object commandParameterValue = this.CommandParameterValue;
			if ((commandParameterValue == null) && this.PassEventArgsToCommand)
			{
				commandParameterValue = parameter;
			}
			if ((command != null) && command.CanExecute(commandParameterValue))
			{
				command.Execute(commandParameterValue);
			}
		}

	}

	protected void EnableDisableElement()
	{
		Control associatedObject = this.GetAssociatedObject();
		if (associatedObject != null)
		{
			if (this.ReadLocalValue(MustToggleIsEnabledProperty) != DependencyProperty.UnsetValue
				&& MustToggleIsEnabled)
			{
				ICommand command = this.GetCommand();
				if (command != null)
				{
					associatedObject.IsEnabled = command.CanExecute(this.CommandParameterValue);
				}
			}
		}
	}
	protected override void OnAttached()
	{
		base.OnAttached();
		this.EnableDisableElement();
	}

	#region Private
	private Control GetAssociatedObject()
	{
		return (base.AssociatedObject as Control);
	}
	private ICommand GetCommand()
	{
		return this.Command;
	}
	private bool AssociatedElementIsDisabled()
	{
		Control associatedObject = this.GetAssociatedObject();
		return ((associatedObject != null) && !associatedObject.IsEnabled);
	}
	#endregion

}

Until that happens though lets hack our way around it cause that’s more fun shall we.
We know also we have to extend it but we do not have access unfortunately to any of its internals.We do have access though to the Command DP since it has to be public.What could we do?
How about replacing (behind the scenes) the original Command with our own Wrapper (Adapter) Command?
Lets call it WeakCommand.It will internally hold on to the original command but this time we will listen to it using a WeakEventListener. WeakCommand will of course itself be an ICommand which will just delegate all calls to and from the original.Nice.Seems that might do the trick.
So how do we “replace” the original command that ETC gets data bound to? We need to listen to it for changes and when it changes we will update it by calling
ETC.Command = new WeakCommand(ETC.Command);

NOTE: This will remove the ViewModel-Command Binding! If for some reason you change your Command from within your ViewModel and expect it to rebind this won’t happen.
That’s an uncommon case though.
This might be solvable as well but not sure yet.Am thinking something along the lines of grabbing the original BindingExpression (and therefore the Binding object) from the Command DP and apply that to BindingListener.Will look into that as well.


This will call ETC’s code to unhook from the Original command (what we wanted) and then immediatelly hook onto our own WeakCommand.
How do we listen for Dependency Property changes when there is no event though?
Easy.We’ll make a BindingListener class with one generic DependencyProperty of type Object and bind that to the Command DP of ETC.This way when ETC.Command changes that surrogate is gonna notify us so we know to replace the command.The binding surrogate is not at all new btw.It’s probably as old as Silverlight.
Hmm.Sounds good but will that work? Of course it will.Would i be making this post if it didnt? 😛

Lets start one by one.The BindingListener :

///
<summary> /// Helper class to be able to listen for DependencyProperty Changes (for example Visibility)
/// </summary>
public class BindingListener : DependencyObject
{
	private readonly Action<Object, Object> valueChangedCallback;

	public BindingListener(Action<Object,Object> valueChangedCallback)
	{
		if (valueChangedCallback == null)
			throw new ArgumentNullException("valueChangedCallback");
		this.valueChangedCallback = valueChangedCallback;
	}

	public object Value
	{
		get { return (object)GetValue(ValueProperty); }
		set { SetValue(ValueProperty, value); }
	}
	public static readonly DependencyProperty ValueProperty =
		DependencyProperty.Register("Value", typeof(object), typeof(BindingListener), new PropertyMetadata(null, OnValuePropertyChanged));

	private static void OnValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
	{
		var source = d as BindingListener;
		if (source != null)
		{
			if (!source.valueChangingBecauseOfUnbind)
			{
				source.valueChangedCallback(e.OldValue, e.NewValue);
			}
		}
	}

	public void Bind(Object source, String sourceProperty)
	{
		var binding = new System.Windows.Data.Binding(sourceProperty);
		binding.Source = source;
		System.Windows.Data.BindingOperations.SetBinding(this, ValueProperty, binding);
	}
	private bool valueChangingBecauseOfUnbind;
	public void UnBind()
	{
		valueChangingBecauseOfUnbind = true;
		Value = null;
		valueChangingBecauseOfUnbind = false;
	}

}

Next up WeakCommand :


///
<summary> /// What it all means (Goal: WE should be able to be garbage collected) :
/// - WE hold a reference to the long living wrapped command
/// - The long living command will hold the Listener instead and NOT us therefore we can die
/// - When we die the long living command stills holds the listener so on the next event
/// he fires the listener will be removed as well.
/// </summary>
public class WeakCommand : ICommand, IDisposable
{
	private WeakEventListener<WeakCommand, Object, EventArgs> weakListener;
	private ICommand wrapped;
	public WeakCommand(ICommand wrapped)
	{
		this.wrapped = wrapped;
		weakListener = new WeakEventListener<WeakCommand, Object, EventArgs>(this);
                //Don't worry.You are not alone.It IS really tricky to understand this 😛
		weakListener.OnEventAction =
			(me, wrappedCommand, args) =>
			{
				//DON'T CLOSURE ANYTHING HERE.USE PARAMETERS ONLY
				if (me.CanExecuteChanged != null)
					me.CanExecuteChanged(wrappedCommand, args);
			};
		weakListener.OnDetachAction =
			(listener) =>
			{
				//If I die then remove the Listener instance as well from wrapped command
				wrapped.CanExecuteChanged -= listener.OnEvent;
			};
		wrapped.CanExecuteChanged += weakListener.OnEvent;
	}

	#region IDisposable
	private bool isDisposed;
	public void Dispose()
	{
		if (!isDisposed)
		{
			weakListener.Detach();
			weakListener = null;
			wrapped = null;
			isDisposed = true;
		}

	}
	#endregion

	#region ICommand
	public bool CanExecute(object parameter)
	{
		ThrowIfDisposed();
		return wrapped.CanExecute(parameter);
	}

	public event EventHandler CanExecuteChanged;

	public void Execute(object parameter)
	{
		ThrowIfDisposed();
		wrapped.Execute(parameter);
	}
	#endregion

	private void ThrowIfDisposed()
	{
		if (isDisposed)
			throw new ObjectDisposedException("WeakCommand");
	}
}

Lets get WeakEventListener in there as well:

// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.

using System.Diagnostics.CodeAnalysis;
using System;

namespace WeakEventListener
{
	///
<summary> /// Implements a weak event listener that allows the owner to be garbage
 /// collected if its only remaining link is an event handler.
 /// </summary>
	/// Type of instance listening for the event.
	/// Type of source for the event.
	/// Type of event arguments for the event.
	[SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Used as link target in several projects.")]
	public class WeakEventListener where TInstance : class
	{
		///
<summary> /// WeakReference to the instance listening for the event.
 /// </summary>
		private WeakReference _weakInstance;

		///
<summary> /// Gets or sets the method to call when the event fires.
 /// </summary>
		public Action OnEventAction { get; set; }

		///
<summary> /// Gets or sets the method to call when detaching from the event.
 /// </summary>
		public Action OnDetachAction { get; set; }

		///
<summary> /// Initializes a new instances of the WeakEventListener class.
 /// </summary>
		///Instance subscribing to the event.
		public WeakEventListener(TInstance instance)
		{
			if (null == instance)
			{
				throw new ArgumentNullException("instance");
			}
			_weakInstance = new WeakReference(instance);
		}

		///
<summary> /// Handler for the subscribed event calls OnEventAction to handle it.
 /// </summary>
		///Event source.
		///Event arguments.
		public void OnEvent(TSource source, TEventArgs eventArgs)
		{
			TInstance target = (TInstance)_weakInstance.Target;
			if (null != target)
			{
				// Call registered action
				if (null != OnEventAction)
				{
					OnEventAction(target, source, eventArgs);
				}
			}
			else
			{
				// Detach from event
				Detach();
			}
		}

		///
<summary> /// Detaches from the subscribed event.
 /// </summary>
		public void Detach()
		{
			if (null != OnDetachAction)
			{
				OnDetachAction(this);
				OnDetachAction = null;
			}
		}
	}
}

Finally its time to start messing with EventToCommand.Here it is :

public class EventToCommandEx : GalaSoft.MvvmLight.Command.EventToCommand
{
	///
<summary> /// Helper to be able to listen to Command changes.
 /// </summary>
	private BindingListener commandBindingListener;

	protected override void OnAttached()
	{
		base.OnAttached();
		commandBindingListener = new BindingListener(
			(oldValue, newValue) =>
				{
					var weakOld = oldValue as WeakCommand;
					if(weakOld != null)
					{
						weakOld.Dispose();
					}
					if (newValue is WeakCommand)
						return; //We were called because we changed the Command below.Ignore
					var newCommand = newValue as ICommand;
					if (newCommand != null)
					{
						this.Command = new WeakCommand(newCommand);
					}
				});
		commandBindingListener.Bind(this, "Command");
	}

	protected override void OnDetaching()
	{
		base.OnDetaching();
		commandBindingListener.UnBind();
		commandBindingListener = null;
	}
}

Have fun looking at those pages getting GCed! Full Source Code Here

If you have read so far then i assume you are interested (hacking IS fun :P) so lets take a look at another way of doing it.
This also has limitations.I’ll get to those after the code.

public class EventToCommandEx : GalaSoft.MvvmLight.Command.EventToCommand
{
	protected override void OnAttached()
	{
		base.OnAttached();
		this.AssociatedObject.Loaded += OnAssociatedObjectLoaded;
		this.AssociatedObject.Unloaded += OnAssociatedObjectUnloaded;
	}

	private ICommand commandBackup;
	protected virtual void OnAssociatedObjectUnloaded(object sender, RoutedEventArgs e)
	{

		if (Command != null)
		{
			commandBackup = this.Command;
			this.Command = null; //Note : We kill the Binding with this.
		}
		else
			commandBackup = null;

	}
	protected virtual void OnAssociatedObjectLoaded(object sender, RoutedEventArgs e)
	{

		if (commandBackup != null)
		{
			//Restore the Command
			this.Command = commandBackup;
		}
		commandBackup = null;

	}
	protected override void OnDetaching()
	{
		base.OnDetaching();
		this.Command = null; //unhook from CanExecuteChanged
		commandBackup = null;
		this.AssociatedObject.Loaded -= OnAssociatedObjectLoaded;
		this.AssociatedObject.Unloaded -= OnAssociatedObjectUnloaded;
	}
}

Ok.So what did we try to do.The idea is that since EventToCommand never unhooks from the event
(Dont be fooled by the Detach method.This is called when the Trigger is removed from the TriggerCollection) a good time to unhook it is probably when the element is removed from the visual tree.Either it was defined in a DataTemplate and the collection binding changed so everything gets refreshed or the user left the Page containing it.Pretty safe.Well not exactly.You have to account for the cases where the same element for some reason gets removed and re-added. That is why, after removing the Command to avoid the leak, we keep a reference to it in case it gets re-added in which case we re-apply.Seems to work nicely but you need to keep these in mind :

  • The Binding gets removed when you set Command = null (same as BindingOperations.ClearBinding() in WPF). If you don’t change the Command from inside the VM ,which i expect you don’t, then it shouldn’t be a problem.
  • You have to know for sure that the element you are attaching to fires Loaded/Unloaded events as expected! I noticed a case with a BindableApplicationBar wrapper that this did not happen.