Sony Arouje

a programmer's log

Posts Tagged ‘Selected Item

Persisting Combo box SelectedItem – Caliburn Micro

with 7 comments

In this post I am going to explain how to persist Selected Item in a Combo box. In my application I have several screens and the user can navigate between them. I need to persist the Combobox’s Selected Item and bind it back when user navigate back to the screen. Here persisting is not db level persistence.

My application is based on Caliburn Micro, a wonderful lightweight MVVM framework.

To persist the selections, I wont create new ViewModel when ever the user clicks on the Navigation button. Only once the instance of the view model will get created. The following code shows the implementation, very simple approach.

FontPropertiesViewModel _fontPropertiesViewModel;
public void GetFontProperties()
{
    if (_fontPropertiesViewModel == null)
        _fontPropertiesViewModel = new FontPropertiesViewModel();
    ActiveScreen = _fontPropertiesViewModel;
}

Let’s examine the xaml file

<UserControl x:Class="MVVMTracer.Pages.Views.FontPropertiesView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    xmlns:ca="clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro"
    mc:Ignorable="d"
    d:DesignWidth="640" d:DesignHeight="480">
    
    <Grid x:Name="LayoutRoot" Background="Transparent" Margin="0,0,10,0">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="25"/>
                <RowDefinition Height="35"/>
                <RowDefinition Height="30"/>
                <RowDefinition Height="30"/>
                <RowDefinition Height="30"/>
                <RowDefinition Height="30"/>
                <RowDefinition Height="35"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="150"/>
                <ColumnDefinition Width="0.555*"/>
            </Grid.ColumnDefinitions>
            <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="Text" VerticalAlignment="Center" FontSize="13.333" Margin="10,0,0,0" Foreground="#FF0F5DA7" Grid.ColumnSpan="2" Width="297"/>
            <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="Font Type" Margin="10,0,0,0" Grid.Row="2" FontSize="11" VerticalAlignment="Center"/>
            <ComboBox x:Name="FontType" Grid.Row="2" Grid.Column="1" VerticalAlignment="Center" FontSize="11" SelectedItem="{Binding SelectedFontType}">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="SelectionChanged">
                        <ca:ActionMessage MethodName="FontTypeSelectionChanged">
                            <ca:Parameter Value="{Binding ElementName=FontType,Path=SelectedItem}"></ca:Parameter>
                        </ca:ActionMessage>
                    </i:EventTrigger>
                </i:Interaction.Triggers>                
            </ComboBox>
            
            <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="Font Size" Margin="10,0,0,0" Grid.Row="3" FontSize="11" VerticalAlignment="Center"/>
            <ComboBox x:Name="FontSize" Margin="0,0,0,0" Grid.Row="3" FontSize="11" HorizontalAlignment="Left" VerticalAlignment="Center" Width="53" Grid.Column="1" SelectedItem="{Binding SelectedFontSize}">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="SelectionChanged">
                        <ca:ActionMessage MethodName="FontSizeSelectionChanged">
                            <ca:Parameter Value="{Binding ElementName=FontSize,Path=SelectedItem}"></ca:Parameter>
                        </ca:ActionMessage>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </ComboBox>
                        
            <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="Font Style" Margin="10,0,0,0" Grid.Row="4" VerticalAlignment="Center" FontSize="11"/>
            <ComboBox x:Name="FontStyle" Grid.Row="4" Grid.Column="1" FontSize="11" VerticalAlignment="Center" SelectedItem="{Binding SelectedFontStyle}">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="SelectionChanged">
                        <ca:ActionMessage MethodName="FontStyleSelectionChanged">
                            <ca:Parameter Value="{Binding ElementName=FontStyle,Path=SelectedItem}"></ca:Parameter>
                        </ca:ActionMessage>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </ComboBox>
            <Button x:Name="Done" Content="Done"  Grid.Row="5" Grid.Column="1" Width="70" HorizontalAlignment="Right" d:LayoutOverrides="Height" VerticalAlignment="Bottom"/>
        </Grid>
    </Grid>
</UserControl>

If you examine the xaml you can see that the selected item of the combo boxes are binded to different properties, also I use ActionMessaging to notify the view model when ever a selection change happen in the Comboboxes. You might wonder why am using ActionMessaging rather than I could bind SelectedItem in two way mode. Yes I tried it first but unfortunately the Selected Item is not showing when user navigates back to the page.

Time to go through the view model

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Caliburn.Micro;
using MVVMTracer.MockServices;
using EmblemDesigner.Controls;

namespace MVVMTracer.Pages.ViewModels
{
    public class FontPropertiesViewModel:PropertyChangedBase
    {
        public FontPropertiesViewModel()
        {
            this.FontType = FontServices.GetFontFamily();
            this.FontStyle = FontServices.GetFontStyle();
        }

        private List<string> _fontType;
        public List<string> FontType
        {
            get { return _fontType; }
            private set 
            {
                _fontType = value;
                NotifyOfPropertyChange(() => FontType);
            }
        }
        private string _selectedFontType;
        public string SelectedFontType
        {
            get { return _selectedFontType; }
            private set
            {
                _selectedFontType = value;
            }
        }
        public void FontTypeSelectionChanged(object selectedItem)
        {
            this.SelectedFontType = selectedItem as string;
        }

        private List<string> _fontSize;
        public List<string> FontSize
        {
            get { return _fontSize; }
            private set
            {
                _fontSize = value;
                NotifyOfPropertyChange(() => FontSize);
            }
        }
        private string _selectedFontSize;
        public string SelectedFontSize
        {
            get { return _selectedFontSize; }
            private set
            {
                _selectedFontSize = value;
            }
        }
        public void FontSizeSelectionChanged(object selectedItem)
        {
            this.SelectedFontSize = selectedItem as string;
        }


        private List<string> _fontStyle;
        public List<string> FontStyle
        {
            get { return _fontStyle; }
            private set
            {
                _fontStyle = value;
                NotifyOfPropertyChange(() => FontStyle);
            }
        }
        private string _selectedFontStyle;
        public string SelectedFontStyle
        {
            get { return _selectedFontStyle; }
            private set
            {
                _selectedFontStyle = value;
            }
        }
        public void FontStyleSelectionChanged(object selectedItem)
        {
            this.SelectedFontStyle = selectedItem as string;
        }
    }
}

Let’s take an eg. of FontType to understand what I am doing here. In the View one of my Combo box name is FontType. Caliburn Micro is intelligent enough to bind the FontType properties in the view model to the Combo box with name FontType in the view. Really great. If you run the application, you can see the FontType combo box is populated with the fonts we added to the FontType properties.

But it’s not enough to persist the user selection. To do so we need to add some more code to the view model. You might have noticed in xaml that the ActionMessage of FontType combo is attached to FontTypeSelectionChanged. When ever the user change selection it will get notified to FontTypeSelectionChanged function in the view model. This function will intern update the SelectedFontType property. The selected SelectedFontType property is binded to FontType’s Combobox’s SelectedItem.

Below diagram shows the communication between the view and the view model what I explained above.

image

One thing I noticed here is the Auto Implemented or Automatic Properties wont work here.

If any better approach pls update me.

Written by Sony Arouje

September 21, 2010 at 12:15 pm

%d bloggers like this: