Let User Clear ComboBox Selection

The built-in ComboBox for Windows 8 does not come with a way to revert the control back to an unselected state. This is an issue in the scenario where the value in the ComboBox isn’t required an thus needs to be clearable.

A simple solution is to add an extra item to the Combox without any text and a value of -1. We can then wire up the CB with an attached property and handle the SelectionChanged event. Whenever we see a value of -1 being selected we can clear the selection.

One of the pros of clearing the CB is the placeholder text. Upon clearing the selection the placeholder text reappears.

The sample attached property can be seen below


public class ComboBoxHelper : FrameworkElement
{

public static bool GetClearOnEmptyValueSelection(DependencyObject obj)
{
 return (bool)obj.GetValue(ClearOnEmptyValueSelectionProperty);
}

public static void SetClearOnEmptyValueSelection(DependencyObject obj, bool value)
{
 obj.SetValue(ClearOnEmptyValueSelectionProperty, value);
}

public static readonly DependencyProperty ClearOnEmptyValueSelectionProperty =
DependencyProperty.RegisterAttached("ClearOnEmptyValueSelection", typeof(bool), typeof(ComboBoxHelper), new PropertyMetadata(false, (o, args) =>
{
 var cb = (ComboBox)o;

 if ((bool)args.NewValue)
 {
  cb.SelectionChanged += (sender, eventArgs) =>
  {
   if (eventArgs.AddedItems.Count == 1)
   {
    if (cb.SelectedValue == null || string.IsNullOrWhiteSpace(cb.SelectedValue.ToString()) || (cb.SelectedValue is int && (int)cb.SelectedValue == -1))
    {
     cb.SelectedIndex = -1;
    }
   }
 };
}
}));
}

 

With the attached property at hand wiring the CB is as simple as:

<ComboBox ap:ComboBoxHelper.ClearOnSelection="true">

Portable Libraries at Campus Days 2013

I will speaking at Campus Days 2013 Wednesday at 10:15 in the Developer track.

This year I will cover Portable Class Libraries (PCL) in .NET.

The talk will briefly introduce the new features and the foundation it is built upon. The main focus of the presentation will be an exploration of the possible and most popular use cases for PCLs. This includes building a clean api, sharing api entities, sharing platform features and sharing view models (in MVVM).

It will be a light presentation. Hope to see you there.

‘The app didn’t start’ Issue

I was presented with this error message upon launching my newly upgraded 8.1 Windows Store app. In the process of upgrading I also upgraded all the related Nuget packages. What I didn’t see was that one of the packages added an App.config file to my Windows Store project.

One hour later…

apparently this App.config causes the app to crash upon activation with no additional information.

Solution: Delete the App.config file from your store project.

Single Column Unscrollable Panel

Let’s say we have a GridView in Windows Store. We want the items arrange according to this:

  • Single column
  • No overflow / scrolling
  • Excess items should not be displayed (and no half displayed items on the bottom edge of the screen)

For some reason there is a no built-in panel that will do this. So I rolled my own. You can see the implementation below:

public class SingleColumnUnscrollablePanel : Panel
{
&nbsp;&nbsp;&nbsp;&nbsp;protected override Size MeasureOverride(Size availableSize)
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var requiredHeight = 0.0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var remainingHeight = availableSize.Height;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var largestDesiredWidth = 0.0;
&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach (FrameworkElement child in Children)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;child.Measure(new Size(availableSize.Width, availableSize.Height));
&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var desiredHeight = child.DesiredSize.Height;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var desiredWidth = child.DesiredSize.Width;
&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (remainingHeight &gt;= desiredHeight)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;largestDesiredWidth = Math.Max(largestDesiredWidth, desiredWidth);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;remainingHeight -= desiredHeight;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;requiredHeight += desiredHeight;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return new Size(largestDesiredWidth, requiredHeight);
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;protected override Size ArrangeOverride(Size finalSize)
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var availableHeight = finalSize.Height;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var currentHeight = 0.0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var mychildren = Children;
&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (!mychildren.Any())
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return finalSize;
&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var largestDesiredWidth = mychildren.Max(s =&gt; s.DesiredSize.Width);
&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach (var child in mychildren)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var desiredHeight = child.DesiredSize.Height;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var desiredWidth = child.DesiredSize.Width;
&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (desiredHeight + currentHeight &gt; availableHeight)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;child.Arrange(new Rect(0, currentHeight, desiredWidth, desiredHeight)); //largestDesiredWidth, desiredHeight));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;currentHeight += desiredHeight;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return new Size(largestDesiredWidth, currentHeight);
&nbsp;&nbsp;&nbsp;&nbsp;}
}

 

Using it in a GridView:

<GridView.ItemsPanel>
<ItemsPanelTemplate>
<controls:SingleColumnUnscrollablePanel />
</ItemsPanelTemplate>
</GridView.ItemsPanel>

Throttling Search Queries On TextChanged With Cancellation Support

Lets imagine a common scenario. The user is typing in a text box trying to search for something in your app. We want to show results as the user types, however, we want to do so without starting a search on every single keystroke. So, we want to wait a little bit after a keystroke, and if no more keystrokes are launched within a small period then we initiate the search. However, if the user starts typing again we want to cancel the previous search.

Describing the scenario is quite simple, but the implemention can quite easily become very messy using conventional approaches.

Lets look at how we can implement the basic searching in response to key presses using Reactive Extensions (RX):

queryTextChangedObservable = 
Observable.FromEventPattern&lt;TextChangedEventHandler, TextChangedEventArgs&gt;
&nbsp;&nbsp; (s =&gt; QTextBox.TextChanged += s, s =&gt; QTextBox.TextChanged -= s);
&nbsp;
queryTextChangedObservable
.ObserveOn(SynchronizationContext.Current)
.Subscribe(async s =&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var textBox = (TextBox) s.Sender;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;await ViewModel.InitiateSearch(textBox.Text);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});

 

We quickly realize that a lot of searches will be initiated. Another problem also arise. Normally RX ensures that calls to a subscription happen in sequential chronological order. However, since we are using an async lamda the  results of our remote request may intertwine and thus no longer be sequential.

Lets start by introducing a throttle that will constrain us from starting search until there is a pause in the key strokes:


queryTextChangedObservable
.Throttle(TimeSpan.FromMilliseconds(350))
.ObserveOn(SynchronizationContext.Current)
.Subscribe(...)

This will initiate a search every time the user stops typing for 350 milliseconds. This solves our first issues. The searches can still overlap though.

A simple way to cancel the previously initiated search would be to introduce a CancellationTokenSource on class level, and make sure we invoke a cancel on it everytime we start a new request:

private CancellationTokenSource cancellationTokenSource;

queryTextChangedObservable
.Throttle(TimeSpan.FromMilliseconds(350))
.Do(s => {if (cancellationTokenSource !=null) cancellationTokenSource.Cancel();})
.ObserveOn(SynchronizationContext.Current)
.Subscribe(async s =>
{
var textBox = (TextBox) s.Sender;
cancellationTokenSource = new CancellationTokenSource();

await ViewModel.InitiateSearch(textBox.Text, cancellationTokenSource.Token);
});

In the above code we use the “side-effect” method Do to explicitly show that we have some nasty side effects. Introducing the class level cancellation token source gets the job done, but it’s not very pretty. We much prefer to model the workflow with as little outside interaction as possible. So how can we model the above without the introduction of a class level variable?

To do this we need to be able to keep track of the previous elements CancellationTokenSource. Scan is nifty method that allows us to accumulate values between calls. We can use this to get access to the previous result and it’s cancellation token source.


<p style="margin-top: 0pt; margin-bottom: 16pt; line-height: 16pt; font-family: Calibri; font-size: 9.75pt; color: #444444;"> queryTextChangedObservable
.Throttle(TimeSpan.FromMilliseconds(350))
.Scan(new {cts = new CancellationTokenSource(), e = default(EventPattern<TextChangedEventArgs>)},
(previous, newObj) => { previous.cts.Cancel();
return new {cts = new CancellationTokenSource(), e = newObj};
})
.ObserveOn(SynchronizationContext.Current)
.Subscribe(async s =>
{
var textBox = (TextBox)s.e.Sender;
await ViewModel.InitiateSearch(textBox.Text, s.cts.Token);
});</p>
<p style="margin-top: 0pt; margin-bottom: 16pt; line-height: 16pt; font-family: Calibri; font-size: 9.75pt; color: #444444;">

This is an immense improvement since we no longer need to introduce a class level variable. The above 4 chained calls succesfully allowed us to throttle the initiated search calls while allowing us to cancel the previous calls. Using async in the subscribe introduce a little gotcha with regard to the sequential ordering, but nothing we couldn’t handle.

To reflect a little about how nice this solution is think about how you would implement this using a conventional approach. You would have to introduce a timer which got reset on every key stroke, then in the timer tick you could initiate searches, which you would then need to cancel in another method. All in all it would be extremely messy.

Using GridView/ListView’s Built-in Animations

The GridView and ListView controls in Windows 8 both come with built-in animation for various operations. When the controls are bound to an ObservableCollection the will do a fancy animation whenever an item is

  • Added to the collection (even if it’s added in the middle of the collection, in which case the other elements will slide away to give room for the new element)
  • Removed from the collection

I mention the two animations/operations above specifically because I rarely see developers taking advantage of this built-in functionality. Most of the time, when applications fetch new data, they simply clear the previous data, and insert the new data, even though there might be elements that were both present in the new and the old data set. This is commonly seen in news/feed application that retrieve new posts — an obvious use for the built animations.

To see an example of these animations in action see my Open Nearby app (You might have to add a location in Denmark, if you are not from here). There is an option to filter the shops in the app bar. When this filter is applied the add/remove operations are used to filter away shops that no longer fit in the result set, and likewise it is filled up with new shops that does.

It can be a hassle to synchronize the old dataset for the GridView/ListView with freshly fetched data. Below is a few extension methods that will make it easier to get going:

public static void SyncCollection&lt;T&gt;(this ObservableCollection&lt;T&gt; observableCollection, IEnumerable&lt;T&gt; dataToSync, Func&lt;T, T, bool&gt; insertBefore, Func&lt;T, T, bool&gt; equality)
{
&nbsp;&nbsp;&nbsp;&nbsp;var recentlyToRemove = observableCollection.Where(s =&gt; dataToSync.All(ss =&gt; !equality(ss,s))).ToList();
&nbsp;&nbsp;&nbsp;&nbsp;var recentlyToAdd = dataToSync.Where(s =&gt; observableCollection.All(ss =&gt; !equality(ss, s)));
&nbsp;&nbsp;&nbsp;&nbsp;foreach (var item in recentlyToRemove)
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;observableCollection.Remove(item);
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;foreach (var item in recentlyToAdd)
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;InsertInOrder(item, observableCollection, insertBefore);
&nbsp;&nbsp;&nbsp;&nbsp;}
}
private static void InsertInOrder&lt;T&gt;(T item, ObservableCollection&lt;T&gt; observableCollection, Func&lt;T, T, bool&gt; insertBefore)
{
&nbsp;&nbsp;&nbsp;&nbsp;for (int i = 0; i &lt; observableCollection.Count; i++)
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (insertBefore(item, observableCollection[i]))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;observableCollection.Insert(i, item);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;// if empty or last
&nbsp;&nbsp;&nbsp;&nbsp;observableCollection.Add(item);
}

 

Here’s an example of usage from Open Nearby:

var newShops = ...// newly fetched shops from data service;

ObservableCollection<Shop> previousShops = ..// the old data current being shown in the view;

Qua.WS.ObservableCollectionExtensions.SyncCollection(previousShops, newShops,
(newShop, oldShop) => newShop.Distance.DistanceInKilometers < oldShop.Distance.DistanceInKilometers,
(shop1, shop2) => shop1.Id == shop2.Id);