Category Archives: ContentControl

Introduction to Data Templates (DataTemplate with ListBox) –Part3

Download the source code from here.

We have seen the Introduction to Templates–DataTemplate in the post here.

In Part2, we have seen the basics of binding data to a ListBox using Inline DataTemplates. It is more common to define it in the resources section so it can be a reusable object, as in the following example:

Creating the DataTemplate as a Resource
<StackPanel.Resources>
    <MyXAMLLocal:Errors x:Key="errorsobj"></MyXAMLLocal:Errors>
    <DataTemplate x:Key="myErrorDataTemplate">
        <StackPanel>
            <TextBlock Text="{Binding Path=PropErrorNumber}" ></TextBlock>
            <TextBlock Text="{Binding Path=PropErrorDescription}"></TextBlock>
            <TextBlock Text="{Binding Path=PropErrorPriority}"></TextBlock>
        </StackPanel>
    </DataTemplate>
</StackPanel.Resources>

 

Now you can use myErrorDataTemplate as a resource, as in the following example:

<ListBox Width="272" Margin="5" HorizontalAlignment="Stretch"
         ItemsSource="{Binding Source={StaticResource errorsobj}}" Height="232"
         ItemTemplate="{StaticResource myErrorDataTemplate}">
</ListBox>

 

Because myErrorDataTemplate is a resource, you can use it with other controls that have a property which takes a DataTemplate type. As shown above, for ItemsControl objects, such as the ListBox, it is the ItemTemplate property. For ContentControl objects, it is the ContentTemplate property.

Let’s improve on the presentation by adding a Border, a Grid, and some TextBlock elements that describe the data that is being displayed.

image

As you can see from the above application, we have displayed the errors in a presentable format and given color identity for the application types.

If the application is a client application type, then the border is in yellow color

If the application is a web application type, then the border is in red color

else by default, for mobile application type, it is blue.

First let us walk through the code that contains the error class information

public class CustomError : INotifyPropertyChanged
    {
        public CustomError()
        {
        }

        public CustomError(string errornumber, string errordescription, int errorpriority, enumapplicationtype apptype)
        {
            this.ErrorType = errornumber;
            this.ErrorDescription = errordescription;
            this.ErrorPriority = errorpriority;
            this.ErrorApplicationType = apptype;
        }

        private string ErrorType;

        public string PropErrorType
        {
            get { return ErrorType; }
            set { ErrorType = value;
            OnPropertyChanged("PropErrorNumber");
            }
        }
        private string ErrorDescription;

        public string PropErrorDescription
        {
            get { return ErrorDescription; }
            set { ErrorDescription = value;
            OnPropertyChanged("PropErrorDescription");
            }
        }
        private int ErrorPriority;

        public int PropErrorPriority
        {
            get { return ErrorPriority; }
            set { ErrorPriority = value;
            OnPropertyChanged("PropErrorPriority");
            }
        }
        private enumapplicationtype ErrorApplicationType;

        public enumapplicationtype PropApplicationType
        {
            get { return ErrorApplicationType; }
            set { ErrorApplicationType = value;
            OnPropertyChanged("enumapplicationtype");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string info)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(info));
            }
        }
    }

    public class Errors : ObservableCollection<CustomError>
    {
        public Errors() : base()
        {
            Add(new CustomError("Error", "Error1", 1, enumapplicationtype.Web));
            Add(new CustomError("Error", "Error2", 1, enumapplicationtype.Mobile));
            Add(new CustomError("Warning","Warning1",2,enumapplicationtype.Client));
            Add(new CustomError("Warning", "Warning2", 2, enumapplicationtype.Web));
            Add(new CustomError("Info", "Info1", 3, enumapplicationtype.Mobile));
            Add(new CustomError("Info", "Info2", 3, enumapplicationtype.Client));
        }
    }

    public enum enumapplicationtype
    {
        Web,
        Client,
        Mobile
    }

 

Like in the previous Part 1 and Part 2, we have Errors observable collection class and the application types are client, web and mobile. We created some default CustomError class values and assigned to the Errors observable collection class.

Let us add the DataTemplate to the Resources section of the Window

<DataTemplate x:Key="myErrorDataTemplate" >
            <Border Name="border" BorderBrush="Blue" BorderThickness="1" Padding="5" Margin="5">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition></RowDefinition>
                        <RowDefinition></RowDefinition>
                        <RowDefinition></RowDefinition>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition></ColumnDefinition>
                        <ColumnDefinition></ColumnDefinition>
                    </Grid.ColumnDefinitions>
                    <TextBlock Grid.Row="0" Grid.Column="0" Text="Task Number:"/>
                    <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Path=PropErrorType}" />
                    <TextBlock Grid.Row="1" Grid.Column="0" Text="Description:"/>
                    <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Path=PropErrorDescription}"/>
                    <TextBlock Grid.Row="2" Grid.Column="0" Text="Priority:"/>
                    <TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding Path=PropErrorPriority}"/>
                </Grid>
            </Border>

            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding Path=PropApplicationType}" >
                    <DataTrigger.Value>
                        <MyXAMLLocal:enumapplicationtype>Web</MyXAMLLocal:enumapplicationtype>
                    </DataTrigger.Value>
                    <Setter TargetName="border" Property="BorderBrush" Value="Red"/>
                </DataTrigger>
                <DataTrigger Binding="{Binding Path=PropApplicationType}" >
                    <DataTrigger.Value>
                        <MyXAMLLocal:enumapplicationtype>Client</MyXAMLLocal:enumapplicationtype>
                    </DataTrigger.Value>
                    <Setter TargetName="border" Property="BorderBrush" Value="Yellow"/>
                </DataTrigger>
            </DataTemplate.Triggers>
       </DataTemplate>

As you can see in the above code, we have defined a DataTemplate with key myErrorDataTemplate and inside the DataTemplate, we are using the customerror class properties and displaying them as per the required format.

we also added some triggers which act on the data at runtime and formats the data displayed as per the data values.

Use the DataTemplate we just created in the XAML code as follows

<StackPanel>
    
    <Label Content="Errors List" FontSize="20"></Label>
    <ListBox ItemsSource="{Binding Source={StaticResource errorsobj}}"
             ItemTemplate="{StaticResource myErrorDataTemplate}"
             IsSynchronizedWithCurrentItem="True"
             HorizontalContentAlignment="Stretch" Height="433" Width="375">
        
    </ListBox>
    <TextBlock FontSize="20" Text="Additional Information:"/>
    <ContentControl Content="{Binding Source={StaticResource errorsobj}}"
                ContentTemplate="{StaticResource myErrorDataTemplate}"/>
</StackPanel>

 

In the above code, we have a list box and its binded to the Errors observable collection class. But then it uses a ItemTemplate which points to the DataTemplate “myErrorDataTemplate” that we created earlier in the code. This formats the data that is presented in the UI.

The complete code of the cs file is as follows

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.ComponentModel;

namespace Introduction_to_DataTemplates_2
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }

    public class CustomError : INotifyPropertyChanged
    {
        public CustomError()
        {
        }

        public CustomError(string errornumber, string errordescription, int errorpriority, enumapplicationtype apptype)
        {
            this.ErrorType = errornumber;
            this.ErrorDescription = errordescription;
            this.ErrorPriority = errorpriority;
            this.ErrorApplicationType = apptype;
        }

        private string ErrorType;

        public string PropErrorType
        {
            get { return ErrorType; }
            set { ErrorType = value;
            OnPropertyChanged("PropErrorNumber");
            }
        }
        private string ErrorDescription;

        public string PropErrorDescription
        {
            get { return ErrorDescription; }
            set { ErrorDescription = value;
            OnPropertyChanged("PropErrorDescription");
            }
        }
        private int ErrorPriority;

        public int PropErrorPriority
        {
            get { return ErrorPriority; }
            set { ErrorPriority = value;
            OnPropertyChanged("PropErrorPriority");
            }
        }
        private enumapplicationtype ErrorApplicationType;

        public enumapplicationtype PropApplicationType
        {
            get { return ErrorApplicationType; }
            set { ErrorApplicationType = value;
            OnPropertyChanged("enumapplicationtype");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string info)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(info));
            }
        }
    }

    public class Errors : ObservableCollection<CustomError>
    {
        public Errors() : base()
        {
            Add(new CustomError("Error", "Error1", 1, enumapplicationtype.Web));
            Add(new CustomError("Error", "Error2", 1, enumapplicationtype.Mobile));
            Add(new CustomError("Warning","Warning1",2,enumapplicationtype.Client));
            Add(new CustomError("Warning", "Warning2", 2, enumapplicationtype.Web));
            Add(new CustomError("Info", "Info1", 3, enumapplicationtype.Mobile));
            Add(new CustomError("Info", "Info2", 3, enumapplicationtype.Client));
        }
    }

    public enum enumapplicationtype
    {
        Web,
        Client,
        Mobile
    }
}

 

The complete code of the XAML file is as follows

<Window x:Class="Introduction_to_DataTemplates_2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
        Title="MainWindow"
        xmlns:MyXAMLLocal="clr-namespace:Introduction_to_DataTemplates_2" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008&quot; xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006&quot; d:DesignHeight="611" d:DesignWidth="426" SizeToContent="WidthAndHeight">
    <Window.Resources>
        <MyXAMLLocal:Errors x:Key="errorsobj"></MyXAMLLocal:Errors>
        <DataTemplate x:Key="myErrorDataTemplate" >
            <Border Name="border" BorderBrush="Blue" BorderThickness="1" Padding="5" Margin="5">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition></RowDefinition>
                        <RowDefinition></RowDefinition>
                        <RowDefinition></RowDefinition>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition></ColumnDefinition>
                        <ColumnDefinition></ColumnDefinition>
                    </Grid.ColumnDefinitions>
                    <TextBlock Grid.Row="0" Grid.Column="0" Text="Task Number:"/>
                    <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Path=PropErrorType}" />
                    <TextBlock Grid.Row="1" Grid.Column="0" Text="Description:"/>
                    <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Path=PropErrorDescription}"/>
                    <TextBlock Grid.Row="2" Grid.Column="0" Text="Priority:"/>
                    <TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding Path=PropErrorPriority}"/>
                </Grid>
            </Border>

            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding Path=PropApplicationType}" >
                    <DataTrigger.Value>
                        <MyXAMLLocal:enumapplicationtype>Web</MyXAMLLocal:enumapplicationtype>
                    </DataTrigger.Value>
                    <Setter TargetName="border" Property="BorderBrush" Value="Red"/>
                </DataTrigger>
                <DataTrigger Binding="{Binding Path=PropApplicationType}" >
                    <DataTrigger.Value>
                        <MyXAMLLocal:enumapplicationtype>Client</MyXAMLLocal:enumapplicationtype>
                    </DataTrigger.Value>
                    <Setter TargetName="border" Property="BorderBrush" Value="Yellow"/>
                </DataTrigger>
            </DataTemplate.Triggers>
       </DataTemplate>
    </Window.Resources>
    <StackPanel>
        
        <Label Content="Errors List" FontSize="20"></Label>
        <ListBox ItemsSource="{Binding Source={StaticResource errorsobj}}"
                 ItemTemplate="{StaticResource myErrorDataTemplate}"
                 IsSynchronizedWithCurrentItem="True"
                 HorizontalContentAlignment="Stretch" Height="433" Width="375">
            
        </ListBox>
        <TextBlock FontSize="20" Text="Additional Information:"/>
        <ContentControl Content="{Binding Source={StaticResource errorsobj}}"
                    ContentTemplate="{StaticResource myErrorDataTemplate}"/>
    </StackPanel>
</Window>

 

Download the source code from here.
Your imagination is your preview of life’s coming attractions. – Albert Einstein

Introduction to Templates–DataTemplate

Download the source code from here.

Most controls have some type of content, and that content often comes from data that you are binding to. In this sample, the data is the name and id of the student. In WPF, you use a DataTemplate to define the visual representation of data. Basically, what you put into a DataTemplate determines what the data looks like in the rendered application. For student name and id to be displayed  and highlighted, you create a DataTemplate as a resource:

            <DataTemplate DataType="{x:Type localXAMLClass:student}" >
                <Border BorderBrush="AliceBlue" BorderThickness="2">
                    <Grid Margin="10">
                        <TextBlock>
                            <Run Text="The Name of the student is "> </Run>
                            <TextBlock Background="LightBlue" Text="{Binding name}"></TextBlock>
                            <Run Text=" And his ID is "></Run>
                            <TextBlock Background="LightBlue" Text="{Binding id}" ></TextBlock>
                        </TextBlock>
                    </Grid>
                </Border>
            </DataTemplate>

Notice that the DataType property is very similar to the TargetType property of the Style. If your DataTemplate is in the resources section, when you specify the DataType property to a type and not assign it an x:Key, the DataTemplate is applied whenever that type appears. You always have the option to assign the DataTemplate with an x:Key and then set it as a StaticResource for properties that take DataTemplate types, such as the ItemTemplate property or the ContentTemplate property.

Before we dive into the data template used in the WPF application let’s see how a simple example works. First take a look at a simple class which represents a student:

namespace IntroductiontoTemplates1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }

    public class student
    {
        private string Name;
        private int Id;

        public string name
        {
            get{return Name;}
            set{Name = value;}
        }

        public int id
        {
            get { return Id;}
            set { Id = value; }
        }
    }
}

 

The student class contains two properties name and id. If we were to display an instance of this class in a ContentControl, the XAML would be something like this:

  1. <Window x:Class="IntroductiontoTemplates1.MainWindow"
  2.         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
  3.         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
  4.         Title="MainWindow" Height="350" Width="525"
  5.         xmlns:localXAMLClass="clr-namespace:IntroductiontoTemplates1" >
  6.     <Grid>
  7.         <Grid.Resources>
  8.             <localXAMLClass:student x:Key="studentXAMLObject" name="kishore1021" id="1"></localXAMLClass:student>
  9.         </Grid.Resources>
  10.         <ContentControl
  11.             Content="{StaticResource studentXAMLObject}" >
  12.         </ContentControl>
  13.     </Grid>
  14. </Window>

 

The UI created by that XAML looks like the following:

image

That certainly isn’t too impressive. What you see above is what gets displayed as a result of calling ToString() on the student object referenced by the ContentControl. Let’s take a moment to examine what is going on here.

The example above creates an instance of the student class, which represents the student kishore1021. It also creates a ContentControl which is told to display that student object somehow. The ContentControl examines the student object and tries to figure out how to render it, but since student does not derive from UIElement it has no way of knowing how to do so. Once ContentControl is devoid of options, it ends up calling ToString() on the student object and then displays that text.

Override the inherited member Object.ToString() implementation.

        public override string ToString()
        {
            return "Returned from ToString() of student class";
        }

 

image

Now that we’ve seen how boring a student object looks in the absence of data templates, it’s time to add one into the mix. Here’s the same XAML used before, only this time there is a template for the student class:

            <DataTemplate DataType="{x:Type localXAMLClass:student}" >
                <Border BorderBrush="AliceBlue" BorderThickness="2">
                    <Grid Margin="10">
                        <TextBlock>
                            <Run Text="The Name of the student is "> </Run>
                            <TextBlock Background="LightBlue" Text="{Binding name}"></TextBlock>
                            <Run Text=" And his ID is "></Run>
                            <TextBlock Background="LightBlue" Text="{Binding id}" ></TextBlock>
                        </TextBlock>
                    </Grid>
                </Border>
            </DataTemplate>

 

Essentially, the DataTemplate in the above example defines that whenever there is a student class object, it should appear as the text “The name of the student is <xyz> And his ID is <322323>. With this DataTemplate, our application now looks like this:

 

image

That is how the XAML renders to show the proper data content: The student object is displayed much more intelligently when a data template is applied. The information held within it is now displayed as part of a sentence, and that sentence is wrapped in a curved blue border. Keep in mind that the rendition of a student object seen above is completely arbitrary. It can be displayed in whatever way is considered appropriate for the application in which it exists.

The complete code of the .cs file is as follows

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace IntroductiontoTemplates1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }

    public class student
    {
        private string Name;
        private int Id;

        public string name
        {
            get{return Name;}
            set{Name = value;}
        }

        public int id
        {
            get { return Id;}
            set { Id = value; }
        }

        public override string ToString()
        {
            return "Returned from ToString() of student class";
        }

    }

}

The complete XAML code is as follows

<Window x:Class="IntroductiontoTemplates1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
        Title="MainWindow" Height="350" Width="525"
        xmlns:localXAMLClass="clr-namespace:IntroductiontoTemplates1" >
    <Grid>
        <Grid.Resources>
            <DataTemplate DataType="{x:Type localXAMLClass:student}" >
                <Border BorderBrush="Red" BorderThickness="2">
                    <Grid Margin="10">
                        <TextBlock>
                            <Run Text="The Name of the student is "> </Run>
                            <TextBlock Background="LightBlue" Text="{Binding name}"></TextBlock>
                            <Run Text=" And his ID is "></Run>
                            <TextBlock Background="LightBlue" Text="{Binding id}" ></TextBlock>
                        </TextBlock>
                    </Grid>
                </Border>
            </DataTemplate>

            <localXAMLClass:student x:Key="studentXAMLObject" name="kishore1021" id="1"></localXAMLClass:student>
        </Grid.Resources>
        
        <ContentControl
            Content="{StaticResource studentXAMLObject}" >
        </ContentControl>
    </Grid>
</Window>

 

Download the source code from here.

 

All men dream but not equally. Those who dream by night in the dusty recesses of their minds wake in the day to find that it was vanity; but the dreamers of the day are dangerous men, for they may act their dream with open eyes to make it possible. – T.E. Lawrence