An alternative ListBox

The ListBox in WPF is your friend. Very useful little control. Simple databinding and ItemTemplate:ing makes it bread and butter, at least for me. BUT, the old white-background-with-blue-background-selected-item style can be a bit dull.

So I did an alternative which looks, if not necessarily nicer at least different from the standard. With a little animation when an item is selected or deselected.

The result looks like this:

The XAML looks like this (below is the only code needed).


<Window x:Class="ListBoxWrapPanel.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <XmlDataProvider x:Key="PeopleData">
            <x:XData>
                <People xmlns="">
                    <Person Name="John" />
                    <Person Name="Peter" />
                    <Person Name="Craig"  />
                    <Person Name="Roger"  />
                    <Person Name="Colin"  />
                    <Person Name="Rodney"  />
                    <Person Name="Nigel" />
                    <Person Name="Godfrey" />
                    <Person Name="Bo"  />
                    <Person Name="Michael"  />
                    <Person Name="Steven"  />
                    <Person Name="Brendan"  />
                </People >
            </x:XData>
        </XmlDataProvider>

        <LinearGradientBrush x:Key="SelectedBrush" StartPoint="0,0" EndPoint="0,1">
            <GradientStop Offset="0" Color="#FFFFFF" />
            <GradientStop Offset="1" Color="#FFFAFAFA" />
        </LinearGradientBrush>

        <LinearGradientBrush x:Key="NotSelectedBrush" StartPoint="0,0" EndPoint="0,1">
            <GradientStop Offset="0" Color="#DEEBFF" />
            <GradientStop Offset="1" Color="#FFFAFAFA" />
        </LinearGradientBrush>
        
        <DataTemplate x:Key="NameplateItemTemplate">
            <TextBlock 
                    HorizontalAlignment="Left"
                    VerticalAlignment="Center"
                    Margin="2"
                    Height="18"
                    Text="{Binding XPath=@Name}"/>
        </DataTemplate>

        <Style x:Key="SelectedItemContainer" TargetType="{x:Type ListBoxItem}">
            <Setter Property="HorizontalContentAlignment" Value="Stretch" />
            <Setter Property="FocusVisualStyle" Value="{x:Null}" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListBoxItem}">
                        <Border 
                                Background="{StaticResource NotSelectedBrush}"
                                CornerRadius="3"
                                BorderThickness="1"
                                BorderBrush="LightGray"
                                x:Name="ContainerBorder"
                                Width="80"
                                Margin="4" >
                            <Border.Effect>
                                <DropShadowEffect 
                                    x:Name="dropShadow"
                                    BlurRadius="3"
                                    ShadowDepth="0"
                                    Color="LightGray"
                                    />
                            </Border.Effect>
                            <Border.RenderTransform>
                                <TranslateTransform x:Name="ContainerBorderTransform"  />
                            </Border.RenderTransform>
                            <ContentPresenter />
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsSelected" Value="true">

                                <Trigger.EnterActions>
                                    <BeginStoryboard>
                                        <Storyboard Duration="0:0:0.1">
                                            <DoubleAnimation
                                                    By="10"
                                                    Storyboard.TargetName="dropShadow"
                                                    Storyboard.TargetProperty="ShadowDepth">
                                                <DoubleAnimation.EasingFunction>
                                                    <CircleEase EasingMode="EaseOut"/>
                                                </DoubleAnimation.EasingFunction>
                                            </DoubleAnimation>
                                            <DoubleAnimation
                                                    By="-10"
                                                    Storyboard.TargetName="ContainerBorderTransform"
                                                    Storyboard.TargetProperty="X">
                                                <DoubleAnimation.EasingFunction>
                                                    <CircleEase EasingMode="EaseOut"/>
                                                </DoubleAnimation.EasingFunction>
                                            </DoubleAnimation>
                                            <DoubleAnimation
                                                    By="-10"
                                                    Storyboard.TargetName="ContainerBorderTransform"
                                                    Storyboard.TargetProperty="Y">
                                                <DoubleAnimation.EasingFunction>
                                                    <CircleEase EasingMode="EaseOut"/>
                                                </DoubleAnimation.EasingFunction>
                                            </DoubleAnimation>
                                        </Storyboard>
                                    </BeginStoryboard>
                                </Trigger.EnterActions>
                                <Trigger.ExitActions>
                                    <BeginStoryboard>
                                        <Storyboard Duration="0:0:0.1">
                                            <DoubleAnimation
                                                    By="-10"
                                                    Storyboard.TargetName="dropShadow"
                                                    Storyboard.TargetProperty="ShadowDepth">
                                                <DoubleAnimation.EasingFunction>
                                                    <CircleEase EasingMode="EaseOut"/>
                                                </DoubleAnimation.EasingFunction>
                                            </DoubleAnimation>
                                            <DoubleAnimation
                                                    By="10"
                                                    Storyboard.TargetName="ContainerBorderTransform"
                                                    Storyboard.TargetProperty="X">
                                                <DoubleAnimation.EasingFunction>
                                                    <CircleEase EasingMode="EaseOut"/>
                                                </DoubleAnimation.EasingFunction>
                                            </DoubleAnimation>
                                            <DoubleAnimation
                                                    By="10"
                                                    Storyboard.TargetName="ContainerBorderTransform"
                                                    Storyboard.TargetProperty="Y">
                                                <DoubleAnimation.EasingFunction>
                                                    <CircleEase EasingMode="EaseOut"/>
                                                </DoubleAnimation.EasingFunction>
                                            </DoubleAnimation>
                                        </Storyboard>
                                    </BeginStoryboard>
                                </Trigger.ExitActions>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    
    <ListBox ItemsSource="{Binding Source={StaticResource PeopleData},XPath=//Person}"
             ItemContainerStyle="{StaticResource SelectedItemContainer}"
             ItemTemplate="{StaticResource NameplateItemTemplate}">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel IsItemsHost="True"  Width="400" />
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
    </ListBox>
</Window>

Threading as Command in MVVM

So far in previous posts (1, 2) I have done some processing work in the background using first BackgroundWorker class and then refine it using the new Task of .NET4.

One of the main purposes of these posts is to learn more about threading and processing stuff in the background.

This time I am trying to wrap this in a reusable manner with MVVM. The following code is greatly inspired by this post: Asynchronous WPF Commands over at SharpFellows.

So, what I wanted to do was to create a way for my application to be able to process long running stuff asynchronous so that my GUI won’t freeze while waiting.

In a MVVM fashion most calls to such long running stuff is initiated via a binding to ICommand

public interface ICommand
{
    event EventHandler CanExecuteChanged;
    bool CanExecute(object parameter);
    void Execute(object parameter);
}

An implementation usually takes two delegates as inputs which are then invoked in CanExecute and Execute. Something like:

...
public DelegateCommand(Action executeMethod, Func<bool> canExecuteMethod=null)
...

In this case my implementation looks like the following:

public TCommandViewModel(IInvoker commandInvoker, Func<bool> canExecuteMethod = null)
{
    if (canExecuteMethod != null)
        this.canExecuteMethod = canExecuteMethod;

    invoker = commandInvoker;
}

and IInvoker looks like this:

public interface IInvoker
{
    void QueueWork();
    event EventHandler WorkFinished;
}

The interesting part of TCommandViewModel looks like this:

public void Execute()
{
    string tempHeader = Header;
    invoker.WorkFinished += (s, e) =>
    {
        IsBusy = false;
        Header = tempHeader;
    };
    IsBusy = true;
    Header = BusyHeader;
    invoker.QueueWork();
}

Basically whats going on is that the execution of “Execute” delegate is handed of to IInvoker, which also reports via the event WorkFinished when execution is completed.

I have made two implementations of IInvoker. First one is the “simple”, the synchronous execution:

public class SyncInvoker : IInvoker
{
    private Action work;

    public SyncInvoker(Action workDelegate)
    {
        work = workDelegate;
        WorkFinished = delegate { };
    }

    public void QueueWork()
    {
        work();
        WorkFinished(this, EventArgs.Empty);
    }

    public event EventHandler WorkFinished;
}

and the second one, the async one, where finally some interesting stuff happens:

public class AsyncInvoker : IInvoker
{
    private Action work;

    public AsyncInvoker(Action workDelegate)
    {
        work = workDelegate;
        WorkFinished = delegate { };
    }
       
    public void QueueWork()
    {
        Task.Factory.StartNew(work)
            .ContinueWith(y => WorkFinished(this, EventArgs.Empty));
    }

    public event EventHandler WorkFinished;
}

So, what happens when QueueWork() is called is that a new Task is created and started via Task.Factory. When finished WorkFinished event is fired.

A command can now be constructed in the viewmodel like this:

public ICommand FetchTweetsCommand
{
    get
    {
        IInvoker invoker = new AsyncInvoker(() =>
            {
                IEnumerable<TwitterStatus> fetchedTweets = LoadTweetsOnPublicTimeLine();
                LoadList(fetchedTweets);
            });

        return new TCommandViewModel(invoker)
        {
            Header = "Load tweets",
            BusyHeader = "Loading..."
        };
    }
}

The property above returs property of type ICommand which is bound to a button in the view. The IInvoker gets a delegate (lambda-style in this case) which loads tweets from the public timeline (takes approx 5 seconds) and loads these in to a bound ObservableCollection.

A nice thing about this is that it’s very easy to call a method/service async only when needed. Replacing the above code with

...
        IInvoker invoker = new SyncInvoker(() =>
            {
                IEnumerable<TwitterStatus> fetchedTweets = LoadTweetsOnPublicTimeLine();
                LoadList(fetchedTweets);
            });
 ...

Will create a command which invokes its execute delegate synchronously. Depending on situation I can easily switch between sync and async way to invoke ICommand’s execute delegate.

Ironically enough, this was written the same day as Microsoft announced the future of C# at PDC. With the new “async” and “await” (or whatever they will be called) keywords, this would probably be much simpler to write.

There’s a bunch of things which I have not included in this. Error handling and cancellation are two obvious thing that comes to mind. Maybe in a future post :-)

BackgroundWorker test, this time with Task

Ok, so naturally I don’t want to be old school and do long time running operations with BackgroundWorker. So I wanted to try to clean up the previous code and rewrite it using Task (new in .NET4) instead of BackgroundWorker.

I wanted to recreate the previous example, with the addition of possibility to run multiple tasks at the same time, without having the UI freeze.

This is what I came up with (setup in MVVM fashion).

ViewModel:

public class NumberCounterTaskViewModel : ViewModelBase
{
    private Task<TimeSpan> task;

    private string infoText;
    private double currentProgressValue;

    public NumberCounterTaskViewModel()
    {
        SetupTask();
    }

    private void SetupTask()
    {
        CurrentProgressValue = 0;

        //  Create a delegate to be invoked in the long time running
        //  service method.
        Action<int> progressUpdatedCallback = i => SetProgress(i);

        //  Creates a new task which will hold a TimeSpan as 
        //  Result property. ALongRunningMethod returns TimeSpan value
        task = new Task<TimeSpan>(() => PseudoService.ALongRunningMethod(progressUpdatedCallback));

        //  When the long running task is finished, we 
        //  want to display the result
        task.ContinueWith(t => SetCompletedTime(t.Result));
    }

    private void SetCompletedTime(TimeSpan ts)
    {
        InvokeOnUIThread(() =>
            {
                InfoText = string.Format("Completed in {0}.{1} sec",
                    ts.Seconds.ToString(),
                    ts.Milliseconds.ToString());
                OnPropertyChanged("StartCommand");
            });
    }

    private void SetProgress(int progress)
    {
        InvokeOnUIThread(() =>
        {
            InfoText = progress.ToString();
            CurrentProgressValue = (double)progress;
        });
    }

    /// <summary>
    /// Property for exposing value to View
    /// </summary>
    public string InfoText
    {
        get { return infoText; }
        set
        {
            if (infoText != value)
            {
                infoText = value;
                OnPropertyChanged("InfoText");
            }
        }
    }

    /// <summary>
    /// Property for exposing value to View
    /// </summary>
    public double CurrentProgressValue
    {
        get { return currentProgressValue; }
        set
        {
            if (currentProgressValue != value)
            {
                currentProgressValue = value;
                OnPropertyChanged("CurrentProgressValue");
            }
        }
    }

    /// <summary>
    /// ICommand for binding the start of task to a button
    /// </summary>
    public ICommand StartCommand
    {
        get
        {
            return new DelegateCommand(
                () => StartCommandExecute(),
                () => StartCommandCanExecute());
        }
    }

    /// <summary>
    /// Execute method for StartCommand.
    /// </summary>
    private void StartCommandExecute()
    {
        //  If we've run the operation once, we reset the task
        if (task.IsCompleted)
            SetupTask();
        task.Start();
    }

    /// <summary>
    /// Defines whether StartCommand can be executed. 
    /// Task cannot be started if its alread running
    /// </summary>
    /// <returns></returns>
    private bool StartCommandCanExecute()
    {
        return task.Status != TaskStatus.Running;
    }

    /// <summary>
    /// Invokes an action on the UI-thread. Needed since 
    /// we do work in the background on another thread
    /// </summary>
    /// <param name="action">Delegate to be invoked on UI thread</param>
    private void InvokeOnUIThread(Action action)
    {
        if (Application.Current != null)
        {
            Application.Current.Dispatcher.BeginInvoke(action);
        }
    }
}

and

public class PseudoService
{
    /// <summary>
    /// Very important and long time running stuff that happens in the background
    /// </summary>
    /// <returns></returns>
    public static TimeSpan ALongRunningMethod(Action<int> progressCallback)
    {
        DateTime before = DateTime.Now;
        int check = int.MaxValue / 100;
        for (int i = 1; i < int.MaxValue; i++)
        {
            if (i % check == 0)
            {
                progressCallback(i);
            }
        }
        return new TimeSpan(DateTime.Now.Ticks - before.Ticks);
    }
}

View:

<UserControl x:Class="TaskTest.NumberCounterTaskView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             xmlns:viewModel="clr-namespace:TaskTest"
             xmlns:sys="clr-namespace:System;assembly=mscorlib"
             d:DataContext="{d:DesignInstance Type={x:Type viewModel:NumberCounterTaskViewModel}}"
             >
    <UserControl.DataContext>
        <viewModel:NumberCounterTaskViewModel />
    </UserControl.DataContext>
    <Border Background="#E7F7F9" BorderBrush="#A3BDED" 
            CornerRadius="3" BorderThickness="4" Margin="2">
    <DockPanel LastChildFill="True">
        <TextBlock
            DockPanel.Dock="Bottom"
            x:Name="textBlock"
            Text="{Binding Path=InfoText}"
            HorizontalAlignment="Stretch"
            VerticalAlignment="Center"
            FontSize="20"
            
            FontWeight="Bold"/>
        <Button
            DockPanel.Dock="Left"
            Command="{Binding Path=StartCommand}"
            Content="Start"
            Height="23"
            Width="75"
            Margin="2"
            x:Name="startButton"
            />
        
        <ProgressBar
            DockPanel.Dock="Right"
            Value="{Binding CurrentProgressValue}"
            x:Name="progressBar"
            Height="23"
            Margin="2"/>
    </DockPanel>
    </Border>
</UserControl>

Added three of these to a stackpanel in a window:

<Window x:Class="TaskTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow"
        xmlns:local="clr-namespace:TaskTest"
    Height="350" Width="525">
    <StackPanel>
        <local:NumberCounterTaskView />
        <local:NumberCounterTaskView />
        <local:NumberCounterTaskView />
    </StackPanel>
</Window>

And you get this:

Three controls that runs a long time running operation in the background while the rest of the UI is active and responsive.

MVVM detail ponderings

So, I am refactoring some of the ViewModel help code I have here at work, and some things bubbled up to consider.

A common scene is to have an ObservableCollection<T> in the viewmodel which is databound to a DataGrid in the View. T in this case is my entities from EF which are implementing INotifyPropertyChanged.

ObservableCollection<T> is very nifty, implementing ICollectionChanged it tells the view when an item is added or removed from the collection. Since my entities implement INotifyPropertyChanged, when an item in the collection has one of it’s properties edited, the view will be notified.

But, what about values that are dependent on values in the collection but is not directly notified via INotifyPropertyChanged?

Consider the following

public class Customer : INotifyPropertyChanged
{
    public double Balance { get; set; }
}

public class CustomerEditViewModel : INotifyPropertyChanged
{
    public CustomerEditViewModel(IEnumerable<Customer> customerList)
    {
        CustomerList = new ObservableCollection<Customer>(customerList);
    }

    public ObservableCollection<Customer> CustomerList { get; set; }

    public double CustomerAverageBalance
    {
        get
        {
            return CustomerList.Average(cust => cust.Balance);
        }
    }
}

Now the CustomerAverageBalance property will be updated when the collection is modified.
But what about if an item in the collection is edited? Quick solution is to loop through the items in the list and subscribe to their PropertyChanged event.

CustomerList.ForEach(cust => cust.PropertyChanged += (s, e) =>
{
    if(e.PropertyName == "Balance")
    {
        OnPropertyChanged("CustomerAverageBalance"));
    }
};

Will do the trick.

Now we are notifying the view every time an item in the collection is changed.</p>
This works as a start, but it is not very elegant in my opinon. Also, when an item is added to the collection, the view will not be updated of it’s PropertyChanged.

So what I’d like to do, is wrap these two events (CollectionChanged and PropertyChanged) together in a (hopefully) more elegant and reusable way. The idea is to have “anything that affects the outcome
This is my helper class which takes care of this.

public class ListCollection<T> : ObservableCollection<T> where T : INotifyPropertyChanged
{
    #region Private fields
    private ICollectionView view;
    #endregion

    #region Public constructors
    public ListCollection() { Setup(); }
    public ListCollection(List<T> list) : base(list) { Setup(); }
    public ListCollection(IEnumerable<T> collection) : base(collection) { Setup(); }
    #endregion

    private void Setup()
    {
        CollectionChanged += (s, e) =>
        {
            if (e.Action == NotifyCollectionChangedAction.Add | e.Action == NotifyCollectionChangedAction.Replace)
            {
                foreach (T item in e.NewItems)
                {
                    item.PropertyChanged += (sender, args) => OnItemPropertyChanged(item, args);
                }
            }
            if (e.Action == NotifyCollectionChangedAction.Remove)
            {
                foreach (T item in e.OldItems)
                {
                    item.PropertyChanged -= (sender, args) => OnItemPropertyChanged(item, args);
                }
            }
        };
    }

    private void OnItemPropertyChanged(T item, PropertyChangedEventArgs e)
    {
        ItemPropertyChangedHandler handler = ItemPropertyChanged;
        if (handler != null)
        {
            handler((T)item, e);
        }
    }

    public event ItemPropertyChangedHandler ItemPropertyChanged;

    public delegate void ItemPropertyChangedHandler(T item, PropertyChangedEventArgs e);
}

It’s a class which inherits ObservableCollection<T> and after initialization it sets up that when the collection is changed, it adds or removes an event handler on the added/removed items. The class exposes an event “ItemPropertyChanged” which is fired every time an item in the collection fires PropertyChanged.
Usage can look like this:

CustomerList = new ListCollection<Customer>(customerList);
CustomerList.ItemPropertyChanged += (s, e) =>
{
    if (e.PropertyName == "Balance")
    {
        OnPropertyChanged("CustomerAverageBalance");
    }
};

Paul Stovell has written about similar problem (Introducing Observal), which could probably solve the above problem also in a very elegant, but for my purposes, too complex way.

BackgroundWorker simple test

So. I wanted to try the BackgroundWorker since it’s been several years since I used it.

I also happened to be a good project for a first simple blog post. If I ever churn out a third post, remains to be seen.

As for the code, it is as simple as it can be. But if anyone can benefit anything from seeing this, it’s all good.

public partial class MainWindow : Window
    {
        private BackgroundWorker worker;

        public MainWindow()
        {
            InitializeComponent();

            worker = new BackgroundWorker();
            worker.DoWork += new DoWorkEventHandler(OnWorkerDoWork);
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(OnWorkerCompleted);
            worker.ProgressChanged += new ProgressChangedEventHandler(OnWorkerProgressChanged);
            worker.WorkerReportsProgress = true;
            progressBar.Minimum = 0;
            progressBar.Maximum = int.MaxValue;
        }

        private void OnWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            textBlock.Text = "Complete";
        }

        private void OnButtonClick(object sender, RoutedEventArgs e)
        {
            if (!worker.IsBusy)
            {
                worker.RunWorkerAsync();
            }
        }

        private void OnWorkerProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            textBlock.Text = e.ProgressPercentage.ToString();
            progressBar.Value = e.ProgressPercentage;
        }

        private void OnWorkerDoWork(object sender, DoWorkEventArgs e)
        {
            int check = int.MaxValue / 100;
            for (int i = 1; i < int.MaxValue; i++)
            {
                if (i % check == 0)
                {
                    worker.ReportProgress(i);
                }
            }
        }
    }

And the XAML:

<Window 
    x:Class="BackgroundWorkerTest.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="MainWindow" 
    Height="350" Width="525">
    <StackPanel>
        <TextBlock 
            x:Name="textBlock" 
            Text="" 
            HorizontalAlignment="Center" 
            VerticalAlignment="Center" 
            FontSize="20" 
            FontWeight="Bold"/>
        <Button 
            Content="Start" 
            Height="23" 
            Name="startButton" 
            Width="75" 
            Click="OnButtonClick"/>
        <ProgressBar 
            x:Name="progressBar" 
            Height="30"/>
    </StackPanel>
</Window>

Hello world!

Naturally being the first post, the first post should be the “Hello world!”-post

namespace HelloWorld
{
 class Program
 {
 static void Main(string[] args)
 {
 Console.WriteLine("Hello World!");
 }
 }
}

the above only to test syntax highlighting.