Feeds:
Posts
Comments

Posts Tagged ‘DataTemplate’

This article is intended for people who already have a solid understanding of data binding, data templates, converters, and WPF in general. In this article I will attempt to show you how to display a collection of items in multiple ways based on some user feedback. Fore example, say you had a collection of person objects and a toggle button on the UI to show a basic or detailed view of the people. Lets say the basic view will only show a person’s first name and photo, while the detailed view would show their last name, address, and special interests (no photo). How could something like this be easily accomplished? Try using DataTriggers and DataTemplates. The following example won’t demonstrate the situation described exactly as above but it will give you the foundation to just that (as well as some other pretty cool things). Now lets get to the code.

First is the MainWindow.cs where I will create two properties. One is a collection of people and the other is an enum value that will be bound to three radio buttons that will allow us to switch between our views of the person collection. For this example, we will allow the user to display each person item as a styled RadioButton, simple TextBlock, or simple CheckBox. Here is all of the code for the MainWindow.cs file.

namespace DataTemplateSwitchingTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
       public ObservableCollection<Person> People
       {
            get
            {
                if (_people == null)
                {
                    _people = new ObservableCollection<Person>()
                    {
                        new Person("Doe", "John", "Johnny"),
                        new Person("Doe", "Jane", "Janie"),
                        new Person("Smith", "Mike", "Big Mike"),
                        new Person("Simpson", "Mark", "El Capitan"),
                    };
                }
                return _people;
            }
        }private ObservableCollection<Person> _people;
        public Element ElementView
        {
            get { return _element; }
            set
            {
                if (value == _element) return;

                _element = value;
                this.OnPropertyChanged("ElementView");
            }
        }private Element _element;

        public MainWindow()
        {
            InitializeComponent();
            ElementView = Element.RadioButtons;
            mainWindow.DataContext = this;
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null)
            {
                var e = new PropertyChangedEventArgs(propertyName);
                handler(this, e);
            }
        }

        #endregion
    }
}

Our Element enum consists of three values, RadioButtons, TextBlocks, and CheckBoxes. This enum allows us to switch the view of our ItemsControl’s content. Below is Xaml for the layout of the page. It is very simple and contains only three radio buttons and the ItemsControl to display the people collection. I will comment on the DataTemplates following the code. I have also not included the SquareRadioButton style here as it is not pertinent to the article but you can find it in the link to the sample project at the end of the article. Here is the MainWindow.xaml.

<Window.Resources>
    <Local:EnumToBooleanConverter x:Key="EnumToBooleanConverter"/>

    <DataTemplate x:Key="RadioButtonTemplate">
        <RadioButton Style="{StaticResource SquareRadioButtonStyle}"
                     Content="{Binding FirstName}"
                     GroupName="People"/>
    </DataTemplate>

    <DataTemplate x:Key="TextBlockTemplate">
        <TextBlock Text="{Binding LastName}"
                   HorizontalAlignment="Center"/>
    </DataTemplate>

    <DataTemplate x:Key="CheckBoxTemplate">
        <CheckBox Content="{Binding Nickname}"
                  HorizontalAlignment="Center"
                  Margin="3">
        </CheckBox>
    </DataTemplate>

    <DataTemplate x:Key="PersonItemTemplate">
        <ContentPresenter x:Name="PeoplePresenter"
                          Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}"
                          ContentTemplate="{StaticResource RadioButtonTemplate}"/>
        <DataTemplate.Triggers>
            <DataTrigger Binding="{Binding ElementName=mainWindow, Path=DataContext.ElementView, UpdateSourceTrigger=PropertyChanged}"
                         Value="{x:Static Local:Element.RadioButtons}">
                <Setter TargetName="PeoplePresenter"
                        Property="ContentTemplate"
                        Value="{StaticResource RadioButtonTemplate}"/>
            </DataTrigger>
            <DataTrigger Binding="{Binding ElementName=mainWindow, Path=DataContext.ElementView, UpdateSourceTrigger=PropertyChanged}"
                         Value="{x:Static Local:Element.TextBlocks}">
                <Setter TargetName="PeoplePresenter"
                        Property="ContentTemplate"
                        Value="{StaticResource TextBlockTemplate}"/>
            </DataTrigger>
            <DataTrigger Binding="{Binding ElementName=mainWindow, Path=DataContext.ElementView, UpdateSourceTrigger=PropertyChanged}"
                         Value="{x:Static Local:Element.CheckBoxes}">
                <Setter TargetName="PeoplePresenter"
                        Property="ContentTemplate"
                        Value="{StaticResource CheckBoxTemplate}"/>
            </DataTrigger>
        </DataTemplate.Triggers>
    </DataTemplate>

</Window.Resources>

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="50" />
        <RowDefinition />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>

    <RadioButton Content="RadioButtons"
                 Style="{StaticResource SquareRadioButtonStyle}"
                 IsChecked="{Binding ElementView, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={x:Static Local:Element.RadioButtons}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
    <RadioButton Grid.Column="1"
                 Content="TextBlocks"
                 Style="{StaticResource SquareRadioButtonStyle}"
                 IsChecked="{Binding ElementView, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={x:Static Local:Element.TextBlocks}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
    <RadioButton Grid.Column="2"
                 Content="CheckBoxes"
                 Style="{StaticResource SquareRadioButtonStyle}"
                 IsChecked="{Binding ElementView, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={x:Static Local:Element.CheckBoxes}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>

    <Grid Grid.Row="1" Grid.ColumnSpan="3" VerticalAlignment="Center" HorizontalAlignment="Center">
        <ItemsControl Width="200" Height="200" Margin="0"
                      ItemsSource="{Binding People}"
                      ItemTemplate="{StaticResource PersonItemTemplate}"/>
    </Grid>

</Grid>

As you can see, there are four data templates. The RadioButtonTemplate, TextBlockTemplate, and CheckBoxTemplate will  change the way a person item is displayed to a RadioButton, TextBlock, and CheckBox (obviously ;o)). Now comes the important part, the PersonItemTemplate. This template has a ContentPresenter that sets the default DataTemplate for a person item to the RadioButtonTemplate. Now, using DataTriggers and property setters, we can change the template to be used when the ElementView enum property changes. Thus, when the user clicks on the CheckBoxes radio button, the people items will then be displayed as check boxes showing just a nickname. The user can click on the TextBoxes radio button and will see only plain text showing last names. Finally, the default template shows each person item as styled radio button showing only first names on the button. Here are some screenshots showing the three views.

Here is a link to the sample project. Happy coding!!

Advertisements

Read Full Post »