Use Reactive Extensions to merge KeyEvents and MouseClicks to close a window

closeAfter reading this post, you’ve learned how to convert MouseClick  and KeyDown events into observable collections. You’ll see how you can even make these collections more convenient by merging them into one stream that tells your window to close with or without saving data.

 

Before we begin

How would you do this with events? Easy. Create a KeyDown event and ButtonClick events.

  •  VirtualKey.Enter -> Close(true)
  • VirtualKey.Escape -> Close(false)
  • ButtonOK.Click -> Close(true)
  • ButtonCancel.Click -> Close(false)

And that is perfectly OK! But you’re here to learn how to do this with Rx (Reactive Extensions). Let’s see how this would work. Start by creating an Observable that pushes KeyDownEvents:

var keys = Observable.FromEventPattern<TypedEventHandler<CoreWindow, KeyEventArgs>, KeyEventArgs>(
    h => Window.Current.CoreWindow.KeyDown += h, 
    h => Window.Current.CoreWindow.KeyDown -= h)
    .Select(pattern => pattern.EventArgs);

Then you create two Observables that pushes ButtonClicks for OK and Cancel:

var okClicks = Observable.FromEventPattern<RoutedEventHandler, RoutedEventArgs>(
    h => ButtonOK.Click += h, 
    h => ButtonOK.Click -= h);

var cancelClicks = Observable.FromEventPattern<RoutedEventHandler, RoutedEventArgs>(
    h => ButtonCancel.Click += h, 
    h => ButtonCancel.Click -= h);

Now merge these streams and subscribe to them. For the Enter and OK Button, pass true to the Close method:

keys.Where(x => x.VirtualKey == VirtualKey.Enter)
  .Select(_ => true).Merge(okClicks.Select(_ => true))
  .Subscribe(Close);

And pass false to the Close method for Escape and the Cancel button:

Add(keys.Where(x => x.VirtualKey == VirtualKey.Escape)
  .Select(_ => false).Merge(cancelClicks.Select(_ => false))
  .Subscribe(Close);

The actual Close method is simplified for this example. Usually you’d write some logic to close a window or popup. Here only the intended action is shown:

private void Close(bool result)
{
  Info.Text = "Window close action: " + result;
  HiddenTextBoxJustToGetTheFocusAwayFromTheClickedButton.Focus(FocusState.Programmatic);
}

Dispose

Don’t forget to dispose the subscriptions. The OnNavigatingFrom in MainPage.xaml.cs in the demo project will show you how.

Use Reactive Extensions to throttle TextChanged events and subscribe to search results

Download the demo project RxSearch

rx

Are you new to Reactive Extensions and looking for a quick tutorial on how to perform a few common tasks in a Windows Store App? In this tutorial you will learn how to throttle TextBox.TextChanged events and use them to search in a collection. You will see how you subscribe to the search results and inform your UI of changes.

Why am I writing about Rx?

wunderAt 6Wunderkinder we make Wunderlist, a multi-platform, multi-user, online/offline, asynchronous application that allows you to organize your life and business.

The multi-user/asynchronous nature of the application presents us with a lot of challenges. We need a local repository (model) that holds the data we need when we create ViewModels that support the Views. But what happens if another user edits data you are looking at right now? A clever sync mechanism changes the model and these changes need to be broadcast to the viewmodels. For this we use Reactive Extensions.

When my colleagues Chris and Martin showed me Rx for the first time, I had no idea what I was looking at. So we started with a very simple example that uses Rx to listen to TextChanged events, throttles them and uses them to perform a search. Then, instead of having a function returning a list of search results, the search function returns an IObservable to which the caller can subscribe. The UI looks like this:

rx

How would you do this without Rx?

  • Add a KeyDown event handler to the TextBox
  • Use a DispatcherTimer to collect a few keystrokes before searching
  • Call a search function and return the result
  • Update the ListBox

Rx allows you to do this in 1 stream of data/events. Let’s start with a fake search function to return some data.

Use Rx to perform the search

  • Start a blank Windows 8.1 app
  • Use Nuget to add Reactive Extensions – Main Library
  • Use Nuget to add Reactive Extensions – XAML Support Library
  • Create class Api.cs and add the following code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;

namespace RxSearch
{
    public class Api
    {
        public IObservable<List<string>> Search(string filter)
        {
            var list = new List<string> { "Vera", "Chuck", "Dave", "John", "Paul", "Ringo", "George" };
            var filteredList = list.Where(x => x.ToLower().Contains(filter.ToLower()));
            return Observable.Return(filteredList.ToList());
        }
    }
}

The Search function does not return a List<string> but an IObservable<List<string>>. This changes a pull-based result to a push-based result. To return a value, we use Observable.Return(list) which returns an IObservable<List<string>> and completes the stream.

Creat the UI in MainPage.xaml:

<Grid Background="#FF96B209">
  <StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
  <TextBox x:Name="textbox" Width="400" Margin="0,0,0,20" FontSize="20"/>
  <ListBox x:Name="listbox" Width="400" Height="400" FontSize="20" />
  </StackPanel>
</Grid>

To use the search you edit MainPage.xaml.cs:

using System;
using System.Collections.Generic;
using System.Reactive.Linq;
using Windows.UI.Xaml.Controls;

namespace RxSearch
{
    public sealed partial class MainPage
    {
        public MainPage()
        {
            InitializeComponent();

            var api = new Api();

            var textchanges = Observable.FromEventPattern<TextChangedEventHandler, TextChangedEventArgs>(
                h => textbox.TextChanged += h,
                h => textbox.TextChanged -= h
                ).Select(x => ((TextBox)x.Sender).Text);

            textchanges
                .Throttle(TimeSpan.FromMilliseconds(300)) // result on threadpool 
                .Select(api.Search)
                .Switch()
                .ObserveOnDispatcher() // send back to dispatcher
                .Subscribe(OnSearchResult);

            api.Search("").Subscribe(OnSearchResult);
        }

        private void OnSearchResult(List<string> list)
        {
            listbox.ItemsSource = list;
        }
    }
}

I split the stream into two parts. The event from the TextBox and the data from the Search result.

TextChanges:

var textchanges = Observable.FromEventPattern<TextChangedEventHandler, TextChangedEventArgs>(
                h => textbox.TextChanged += h,
                h => textbox.TextChanged -= h
                ).Select(x => ((TextBox)x.Sender).Text);

textchanges is now an IObservable<string> that is…well…observable. To observe it, we subscribe to it.

Subscribe to IObservable

Update!

In my initial post I used SelectMany to get to the actual data. Then I got this feedback from  the Rx creators themselves.

switch

So I tried Select().Switch() and it works beautifully!

textchanges
 .Throttle(TimeSpan.FromMilliseconds(300)) // result on threadpool 
 .Select(api.Search)
 .Switch()
 .ObserveOnDispatcher() // send back to dispatcher
 .Subscribe(OnSearchResult);

And that’s really it. OnSearchResult is just a handler to actually fill the ListBox:

 private void OnSearchResult(List<string> list)
        {
            listbox.ItemsSource = list;
        }

Download the demo project RxSearch

Change XAML designer background color in Visual Studio

If you use the Visual Studio 2013 XAML designer with the light theme enabled and you are designing user controls or pages with transparent backgrounds, it might be hard to read the text:

vsbefore

Solution

One quick solution is to change the XAML UI Designer colors.

  • Click TOOLS > OPTIONS… > Environment > Fonts and Colors
  • Under Show settings for choose XAML UI Designer
  • Change Item foreground and Item background to the same color to prevent a checkerboard pattern

 

vscolor

Now you can read your text again:

vsres

Cross platform development with C#

phoneAre you writing apps for multiple platforms? Do you wonder what you can and cannot share when writing C# for Windows Phone, Windows 8 and WPF?

Me and Christian Lang tell you all about it! We’ve prepared a great talk where you learn how to write an application and convert it to a multi-targeted app. The goal is to write native apps that respect the UI paradigms and capabilities of the platform, while sharing as much of the code as possible in the Business and Data layer:

share

We talked & coded at the .NET user group here in Berlin:

cross

And we will do it again at Spartakiade (March 23, 2014) and at Developer Week 2014 (July 14-17, 2014) in Nürnberg.

Interested?

Come see us talk about Cross Platform development with C# at Spartakiade in Berlin or Developer Week in Nürnberg. Can’t make it? Send me an email (loek@6wunderkinder.com) to discuss the possibilities to talk at your company!

First aid for detecting memory leaks in a Windows Store App

fix-water-leak-reno-lg1Before submitting your Windows 8 app to the Windows Store, it never hurts checking for memory problems. This article is about detecting these problems in an early stage of development. I’ll show you a super easy trick to do this without the need for memory profilers. The solution is to put a TextBlock on each page that shows the memory currently in use. The good thing is that after a while you get an understanding about how much memory your app “should use”. If this changes suddenly, you are in a good position to guess why it happened and the solution is only one Git-action away.

Showing memory usage on your page

  • Put this TextBlock in your MainPage.xaml
<TextBlock TextWrapping="Wrap" x:Name="mem" FontSize="21.333"/>
  • And add the following code to your OnNavigatedTo event handler in MainPage.xaml.cs:
mem.Text = "Memory in use: " + Math.Round(GC.GetTotalMemory(true) / 1000000.0, 2) + "mb";

Now see what happens if I navigate between 2 pages in my app. Watch the MEMORY USE text in the left upper corner:

mem

Clearly my app has a major memory leak. If your memory increases with 1 MB each time you navigate, older pages are probably not garbage collected.

Meten is weten!

Indicating memory leaks is as simple as adding 2 lines of code to each page. It will help you to get a good feeling of memory usage regardless of problems.