Monday, 23 July 2012

UI: Good setup interface

Metro Studio is one of the coolest application I have seen with the coolest UI interfaces.

Check out its setup interface:

image

image

And the application:

image

Friday, 20 July 2012

70-511 Windows App Dev Certification

Happy to share that I have cleared the exam for the - 70-511 TS: Windows Applications Development with Microsoft .NET Framework 4 - certification.

The exam is a tough one covering almost all the topics with sufficient depth.

How did I prepare?
- I took a hard look at the 'skills measured' or the exam objectives to find out what I knew well and what I didn't.
- Bought these two books:


  
WPF 4 Unleashed and MSPress Self-Paced Training Kit

- WPF Unleashed I basically read almost from cover to cover, except few topics like 3D and easing functions (3d is not in exam but easing function is, I just didn't have time in the end to cover easing functions)
- MSPress book also I went through all chapters.
- But these things would not matter if you don't have experience of at least 1.5-2 years of developing real world WPF applications.

Benefits:
I have certainly gained a deep understanding of the technology and appreciate it a lot more now. There are few things that I did not know, for instance animation classes are really easy and wonderful to use. In my job, coding in WPF has become a lot more 'flowy', now there are no apprehensions/doubt about how some parts of the framework work.

Tuesday, 10 July 2012

WPF: View Model Communication

Recently we had a requirement in our project to establish communication between two view models.

The user interface design and their data context values:

 image

The ‘User Control 1” (UC1) has a grid showing the list of business products and ‘User Control 2’ (UC2) a grid with categories of products. The categories and products can be added/removed/changed by the user.

We had a business case that – if the category is removed by the user on UC2 then what should happen to the products on UC1 which are using that category? It was decided to delete those products and it should happen automatically – that is the deletion of category should trigger the deletion of product from the list.

The model contains the observable collection of Products and Categories and bound to the grids on the UI. The categories are deleted with the help of button in one of the columns, this button is connected to a DeleteCommand in the UC2 view model which deletes the selected category from the list.

So how can we “do something” on the products view model when something happens on categories’? What are the options?

- Attach to the Categories collection changed event.
- Pass the product view model to the categories so that categories can call some method like Changed() on product’s view model
- Or we could also let the Categories view model go ahead and delete the product from the Model itself thus automatically reflecting on the product’s grid.

You can see there are problems with all these options – the first two create tight coupling between the view models. And the last one doesn’t couple but does something more terrible – changing the Model that it doesn’t own. It is not meaningful or intuitive for a view model to change a Model class which it does not use on its bound UI and more importantly it violates the single responsibility principle (SRP).

However there is an elegant solution. MVVM Foundation (a framework) offers a Messenger class which facilitates view model communication. It uses Mediator pattern so that there is minimum dependency. Let’s see the code.

1. First a static class which can be used by all the view models.

public static class ViewModelCommunication
{
static ViewModelCommunication()
{
Messaging = new Messenger();
}

//a singleton object for view model communication
public static Messenger Messaging { get; set; }

//list of messages
public static string CategoriesChanged { get { return "CategoriesChanged"; } }
}

We create a “ViewModelCommunication” class which is a static class with a static constructor which initializes the “Messenger”. Also we create a static property for “CategoriesChanged” which can be used by any module to register for this message or raise this message. Additional messages could be added for other message types.


2. Next we modify Product view model to register for notification

ViewModelCommunication.Messaging.Register(ViewModelCommunication.CategoriesChanged, (Action) 
delegate()
{
Refresh();
}
);
We use the “Register” method on Messenger class to register our message – CategoriesChanged and assign a delegate to be called whenever such message is received. In our code, the ‘Refresh()’ method would be called whenever the user changes a category.

3. Categories view model raises the alert

//notify messaging colleagues
ViewModelCommunication.Messaging.NotifyColleagues(ViewModelCommunication.CategoriesChanged);


The Categories view model sends notification whenever its own Categories collection changes.
And we are done!

Avoiding Memory leaks

One internal detail – the Messenger class uses a sub-class of WeakReference so that the memory is not leaked (link). Otherwise in our example, let’s say Categories and Products show up on a different windows which can be closed. So when the Products window is closed, the Messaging class will still maintain a reference to it as it points to the delegate – thereby product’s view model would not be GC’ed leading to memory leaks. Using WeakReference solves this problem.

Saturday, 7 July 2012

WPF: Customizing ComboBox

(Edit: This turned out to be a very long post so take a cup of coffee and enjoy!)
Problem statement: We need to customize the Combo Box's template by adding an 'Add' button as one of the items in the list.

Background: Let's say we have a list in our model - a list of supplier. This list of suppliers is bound to a combo box. The user needs to select a supplier to complete a business case.  Now the users ask for an 'Add' button, and they want it as one of the items in the combo box.
Approach 1: Let's consider that the list is not in model/view model but contained in XAML.
For e.g.:

            <ComboBox>
                <ComboBoxItem>Supplier 1</ComboBoxItem>
                <ComboBoxItem>Supplier 2</ComboBoxItem>
                <ComboBoxItem>Supplier 3</ComboBoxItem>
                <ComboBoxItem>Supplier 4</ComboBoxItem>
           
</ComboBox>

In this case, we can add the Button as a child of ComboBox:

            <ComboBox height="25" x:name="cmbSupplier">
                <ComboBoxItem>Supplier 1</ComboBoxItem>
                <ComboBoxItem>Supplier 2</ComboBoxItem>
                <ComboBoxItem>Supplier 3</ComboBoxItem>
                <ComboBoxItem>Supplier 4</ComboBoxItem>
                <Button click="Button_Click" Content="Add" />

           
</ComboBox>








 


The Button_Click event:

cmbSupplier.Items.Insert(cmbSupplier.Items.Count - 1, "New Supplier");

Now comes the saving part. How do we save the new supplier? We have given the 'default' list in XAML so it's kind of hard-coded which is not a good thing, it should ideally come from persistence store like database or an XML file. But say we add the default supplier's in XAML and the user can add more. So we can get the newly added suppliers from Combo Box's items list in code-behind and persist them. On loading the application again we can add these 'new' supplier again.

The downside here is that it uses code-behind and there no data binding. The Combo box is not bound to a list and we are using click event of the button not a Command.

MVVM: The above approach can be used in certain exceptional cases. Normally we use MVVM pattern and we bind the Combo box ItemsSource property to a collection in our view model. So what can we do in this case? Again we have more than one option, but first let me build the MVVM infrastructure before customizing the Combo Box.

In our model we have:

    public class Supplier
    {
        public string Name { get; set; }
        public int Code { get; set; }
    }

(We should have the notify property change as well in the properties, but I am keeping things simple here as we focus on adding a new item and not updating existing one.)

Note: I am using MVVMFoundation framework that's why you see the RelayCommand and ObservableObject.

This is our view model:
    public class ViewModel : ObservableObject
    {
        public ICommand AddSupplierCommand { get; set; }
        public ObservableCollection Suppliers { get; set; }
        public ViewModel()
        {
             Suppliers = new ObservableCollection();
             FillSuppliers(); //method to get supplier list from a store
            AddSupplierCommand = new RelayCommand(AddSupplier);
        }
        private void AddSupplier()
        {
            Suppliers.Add(new Supplier { Name = "New Supplier", Code = 999 });
        }
    }

In XAML:
<ComboBox Height="25" ItemsSource="{Binding Suppliers}">
</ComboBox>

In Window's code-behind:
     public partial class Window2 : Window
    {
        ViewModel _vm;
        public Window2()
        {
            InitializeComponent();
            _vm = new ViewModel();
            this.DataContext = _vm;
        }
    }

And we get:



So now we add a data template in XAML to show the name of supplier and not the ToString() implementation.

We change the XAML to:

            <ComboBox Height="25" ItemsSource="{Binding Suppliers}">
                <Combobox.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Margin="5,5" Text="{Binding Name}" />
                     </DataTemplate>
                </ComboBox.ItemTemplate>
            </ComboBox>

And the result is:



Great, so now we have everything to start adding the 'add button.

Approach 2 Using a Composite Collection: Composite collections is a recent find for me. From MSDN - "Enables multiple collections and items to be displayed as a single list."

I think that's perfect for us since we want to add different type of objects to a list. Let me show you the code first and then we will discuss it.

Window resources in XAML: ("vm" is namespace of the project, ViewModel is the class name)
    <Window.Resources>
        <vm:viewmodel x:key="viewmodel"></vm:viewmodel>
    </Window.Resources>

We change the XAML to:
            <ComboBox height="25">               
                <ComboBox.ItemSsource>
                    <CompositeCollection>
                        <CollectionContainer Collection="{Binding Source={StaticResource viewmodel}, Path=Suppliers}" />
                        <Button Command="{Binding Source={StaticResource viewmodel}, Path=AddSupplierCommand}" Content="Add" />
                    </CompositeCollection>
                </Combobox.ItemsSource>
             </ComboBox>
             
Window.xaml.cs:
    public partial class Window2 : Window
    {
        public ViewModel ViewModel { get; set; }
        public Window2()
        {
            InitializeComponent();
            this.ViewModel = new ViewModel();
            this.DataContext = this.ViewModel;
            if (this.TryFindResource("viewmodel") != null)
            {
                this.Resources["viewmodel"] = this.ViewModel;
            }
          }
    }

There are couple of hacks here:

- Using CompositeCollection in XAML has a problem. It has no visual properties and is not found in Visual tree - so it doesn't inherit the data context we set in code-behind. So this <CollectionContainer Collection="{Binding Suppliers}"></CollectionContainer> doesn't work.
As a workaround we add the ViewModel object to Resources (later we will see why we are adding the entire view model not just the "Suppliers" list), and refer this resource as a StaticResource in CompositeCollection. It is worth mentioning here that you could also use MultiBinding to which you pass in the two collections and get back the full combined collection.
- We have removed the DataTemplate. This is because now we cannot use a DataTemplate since we have two different types of objects (Supplier and Button) in our collection. We can use a DataTemplateSelector but by using that here we will deviate from our topic, so I have just changed the ToString() in Supplier class to return the "Name" property for now.
- For the Button, we are setting its Command property - again from the ViewModel static resource, because we can't access the DataContext here (this why we store the entire view model in resources).

The result is:



And upon clicking 'Add' we get:



Great, here we can use databinding, MVVM pattern and get the added supplier in our Model. Only problem is using DataTemplate - which can be resolved by DataTemplateSelector. Next we will see another approach where we can actually use a DataTemplate. Other problem is adding the view model in resources.

Approach 3 Using Converters: This approach doesn't use the CompositeCollection. Some people may not like the idea of setting the DataContext and also adding ViewModel object in the resources.

So here we take a different approach - we change the Supplier list to show the 'Add' button.

Let's suppose we get this Suppliers data from our Model:
- Name: Supplier 1, Code: 100
- Name: Supplier 2, Code: 200
- Name: Supplier 3, Code: 300
- Name: Supplier 4, Code: 400

Now just after loading this data we add a "dummy" supplier to the list:
- Name: Supplier -1, Code:-1

Our XAML becomes:

In the resources we add two converters:

     <Window.Resources>
        <vm:SupplierToVisibilityConverter x:Key="supplierToVisibilityConverter" />
        <vm:SupplierToVisibilityForAddConverter x:Key="supplierToVisibilityForAddConverter" />
    </Window.Resources>

The ComboBox:

            <ComboBox Height="25" ItemsSource="{Binding Suppliers}" Style="{StaticResource ResourceKey={x:Type ComboBox}}" >
                <ComboBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <TextBlock Margin="5,5" Text="{Binding Name}" Visibility="{Binding Path=., Converter={StaticResource supplierToVisibilityConverter}}"/>
                            <Button Content="Add" Margin="5,5"
                                    Command="{Binding  RelativeSource={RelativeSource AncestorType={x:Type ComboBox}}, Path=DataContext.AddSupplierCommand}"
                                    Visibility="{Binding Path=.,Converter={StaticResource supplierToVisibilityForAddConverter}}"/>
                        </StackPanel>
                    </DataTemplate>
                </ComboBox.ItemTemplate>               
            </ComboBox>

ViewModel:
    public class ViewModel : ObservableObject
    {
        public ICommand AddSupplierCommand { get; set; }
        public ObservableCollection Suppliers { get; set; }
        public ViewModel()
        {
            Suppliers = new ObservableCollection();
            AddSupplierCommand = new RelayCommand(AddSupplier);
            _dummy = new Supplier { Name = "-1", Code = -1 };
            FillSuppliers();
        }
        Supplier _dummy;
        private void AddSupplier()
        {
            Suppliers.Remove(_dummy);
            Suppliers.Add(new Supplier { Name = "New Supplier", Code = 999 });
            Suppliers.Add(_dummy);
        }
        void FillSuppliers()
        {
            Suppliers.Add(new Supplier { Name = "Supplier1", Code = 1 });
            Suppliers.Add(new Supplier { Name = "Supplier2", Code = 2 });
            Suppliers.Add(new Supplier { Name = "Supplier3", Code = 3 });
            Suppliers.Add(new Supplier { Name = "Supplier4", Code = 4 });
            Suppliers.Add(_dummy);
        }
    }

Explanation:

In the ViewModel, you can see that we are adding a dummy supplier with name and code of value -1. In the DataTemplate of ComboBox we have two controls - TextBlock to see the Supplier details and one Button. Now since DataTemplate is called for every item in the list, we need a way to make visible and hide the TextBlock and Button - based on the supplier item.

For this we use two converters (we could have used one but keeping things simple for now). The converters are SupplierToVisibilityConverter and SupplierToVisibilityForAddConverter:

    public class SupplierToVisibilityConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            var supplier = value as Supplier;
            if (supplier != null)
            {
                if (supplier.Code == -1)
                    return Visibility.Collapsed;
                return Visibility.Visible;
            }
            return Binding.DoNothing;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return Binding.DoNothing;
        }
    }

    public class SupplierToVisibilityForAddConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            var supplier = value as Supplier;
            if (supplier != null)
            {
                if (supplier.Code == -1)
                    return Visibility.Visible;
                return Visibility.Collapsed;
            }
            return Binding.DoNothing;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return Binding.DoNothing;
        }
    }

In SupplierToVisibilityConverter we check whether the current supplier item has Code == -1, if yes then we hide it else keep it visible. As you can see in XAML this converter is used in TextBlock's visibility. Similarly we use the SupplierToVisibilityForAddConverter for finding out whether the 'Add' button should be visible or not.

Also in the Button, we have used RelativeResource to bind the Command. This is because the AddSupplierCommand is available on the ViewModel and in the DataTemplate we have access only to the current Supplier item being bound. So we refer to the DataContext of the parent ComboBox.

The output:



The disadvantages of this approach are:
- Using converters complicates the logic a little. Although they can be reused for other scenarios as well
- Adding a dummy entry in the list is also not a good idea. This is changing the Model data for a UI hack, so the developer persisting the data needs to be aware about this hack. Necessary sould also be done that in ViewModel to not let the dummy data go out.

Approach 4 Using Control Template (with attached property): Control templates are modified when we need to change the UI of the control. It gives full freedom to change the layout, behavior, look and feel of the control.

I am using this tool http://thematic.codeplex.com/ to create custom styles. If you use this tool, you will see a file named "combobox.xaml" in the list of generated files.

I am showing here the portion that relevant to our discussion:

    <!--<SnippetComboBoxStyle>-->
    <Style x:Key="{x:Type ComboBox}" TargetType="ComboBox">
        <Setter Property="SnapsToDevicePixels" Value="true"/>
        <Setter Property="OverridesDefaultStyle" Value="true"/>
        <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
        <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ComboBox">
                <Grid>
    ....
            <Popup
              Name="Popup"
              Placement="Bottom"
    ....
                    <ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True">
                        <StackPanel Orientation="Vertical">
                            <StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
                            <Button Margin="5,5" Content="Add" Command="{TemplateBinding app:CommandExtensions.Command}"
                                    Background="{StaticResource WindowBackgroundBrush}"/>
                        </StackPanel>
                    </ScrollViewer>
    .....
                    </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

I have added the lines in bold. The ComboBox has a scroll viewer to scroll the items which we find in the ScrollViewer control. A StackPanel with IsItemsHost="true" is used to display the items. So just after this stack panel we add our 'Add' button.

XAML:
        <ComboBox Height="25" ItemsSource="{Binding Suppliers}" Style="{StaticResource ResourceKey={x:Type ComboBox}}"
                vm:CommandExtensions.Command="{Binding AddSupplierCommand}" />
 
Result:



Ok so we have the button but how do we hook the Button with a command? ComboBox doesn't have a Command property which we can use here. And if we had created a custom control by inheriting the ComboBox we could have created a new Dependency Property called Command and used it.

Attached properties to the rescue. This is a perfect scenario for using attached properties, so let's create one.

Create a new class for this code:

    internal class CommandExtensions : DependencyObject
    {     
        public static ICommand GetCommand(DependencyObject obj)
        {
            return (ICommand)obj.GetValue(CommandProperty);
        }

        public static void SetCommand(DependencyObject obj, ICommand value)
        {
            obj.SetValue(CommandProperty, value);
        }

        // Using a DependencyProperty as the backing store for Command.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CommandProperty =
            DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(CommandExtensions), new UIPropertyMetadata(null)); 
    }

In the XAML we use the new attached property:
        <ComboBox Height="25" ItemsSource="{Binding Suppliers}" Style="{StaticResource ResourceKey={x:Type ComboBox}}"
                vm:CommandExtensions.Command="{Binding AddSupplierCommand}" />

Approach 5 Using Custom Control:  Finally we could also create a custom control by inheriting the ComboBox class. (code coming soon...)


Shorts - week 3, 2022

Post with links to what I am reading: 1. A very good post on different aspects of system architecture: https://lethain.com/introduction-to-a...