Category Archives: WPF

My experiences with WPF

Basics of Command Binding Using ICommand

ICommand is used to define a command. The interface contains the following information.

public interface ICommand
{
    //has 2 methods
    void Execute(object parameter);
    bool CanExecute(object parameter);

    //1 event
    event EventHandler CanExecuteChanged;
}

ICommand interface consists of the following:

Two methods:
CanExecute : Defines the method that determines whether the command can execute in its current state.
Execute : Defines the method to be called when the command is invoked.

One Event:
CanExecuteChanged: Occurs when changes occur that affect whether or not the command should execute.

You implement the ICommand interface on a class, provide a way for command handlers to hook up, and then do the routing when the command is invoked. You also must decide what criteria you will use for determining when to raise the CanExecuteChanged event. Using custom ICommand implementations allows us to provide our own routing mechanisms, particularly ones that are not tied to the visual tree and that can support multiple command handlers. Given an instance of an ICommand, you just call Execute, and it does whatever it’s supposed to do. Except you shouldn’t call it if it’s CanExecute is false. If you want to know when CanExecute might be willing to give you a different answer, listen to the CanExecuteChanged event.

Lets try a simple hello world application using the IComand. First, declare a class derived from ICommand and name it as MyFirstCommand. Since the class MyFirstCommand is derived from ICommand, we need to implement the interface as shown below. Whenever the command is executed, it calls the Execute() method to show a Hello World message box.

public class MyFirstCommand : ICommand
{
    public void Execute(object parameter)
    {
        MessageBox.Show("Hello world");
    }

    public bool CanExecute(object parameter)
    {
        return true;
    }
    public event EventHandler CanExecuteChanged;
}

 

Once you have an ICommand instance handy, you can give it to a Button (on the Button.Command property), and Button knows what to do with it. As the simplest example, you can do this with the previous command:

First, we need to create get the class namespace into XAML using the following code. To know more about Instantiating an Object as a resource in XAML see the link https://kishore1021.wordpress.com/2010/02/06/instantiating-an-object-as-a-resource-in-xaml/

xmlns:local="clr-namespace:CommandBinding2"

 

Create a resource in the Grid class as shown below.

<Grid.Resources>
            <local:MyFirstCommand x:Key="hwc"/>
        </Grid.Resources>

Create a button inside the grid and assign the resource we created in the above code to the button command property.

Button Content="Hello World" Height="36" HorizontalAlignment="Left" Margin="12,115,0,0" Name="button1" VerticalAlignment="Top" Width="116"
                Command="{StaticResource hwc}"/>
   

 

If you do that, you’ll notice that the Button is enabled. In the CanExecute() method, if we have not returned true, then the button would have appeared as disabled. That’s because Button knows to call CanExecute, but we haven’t specified a parameter, and recall from above that if you pass null as an argument to CanExecute it returns false. So Button has a CommandParameter property that lets you specify what will be passed to CanExecute and Execute:

Now the button is enabled, and if you click on it, you’ll see “Hello, world” in the debug output window.

This actually isn’t just a Button feature, it’s actually in the base class ButtonBase. And MenuItem is a ButtonBase. So MenuItem can use the ICommand too. If MenuItem’s Command property is set to the Static resource hwc, it will also behave the same.

Passing parameter to the Command

Lets go through the hello world code discussed above and change it a bit to use the command parameters. In the Button class, set the CommandParameter property to some text like “Hello, World” as shown in the following code.

<Button Content="Hello World" Height="36" HorizontalAlignment="Left" Margin="12,115,0,0" Name="button1" VerticalAlignment="Top" Width="116"
                CommandParameter="Hello, World"
                Command="{StaticResource hwc}"/>
    

 

In the code file, change the Execute() method to show the parameter passed to the command. Modify the CanExecute() method to return true if the command parameter contains a value otherwise return false as shown in the following code.

public class MyFirstCommand : ICommand
{
    public void Execute(object parameter)
    {
        MessageBox.Show(parameter.ToString());
    }

    public bool CanExecute(object parameter)
    {
        if (parameter != null)
            return true;
        else
            return false;
    }
    public event EventHandler CanExecuteChanged;
}

 

Run the project and see the magic yourself.

Going further with ICommand:

 

image

Figure 1: Class diagram of the participating classes

A good starting point for creating a custom command is to use delegates. A delegate already supports invocation of a target method, and it also supports multiple subscribers. In the above diagram, have a student class and a UISaveCommand class that the MainWindow uses. The idea is that when I click on Save Button as shown in Fig 2, it should call the Save() method. But the Button Command doesn’t know where the Save() method is present. So the UISaveCommand class uses the Func<>.

image

Figure 2: Output window

Step 1:

Let us create a UISaveCommand class derived from ICommand interface and implement the interface in that class as shown below. In the CanExecute() method we are checking to see if the function pointer (funcpointer) is pointing to a valid or not. If it points to a valid function, we return true otherwise return false. The Execute() method just calls the method pointed to by the function pointer (delegate).

public class UISaveCommand : ICommand
{
    public Func<int> funcpointer
    {
        get;
        set;
    }

    public bool CanExecute(object parameter)
    {
        if (funcpointer != null)
        {
            return true;
        }
        else
            return false;

        throw new NotImplementedException();
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void Execute(object parameter)
    {
        if (funcpointer != null)
        {
            funcpointer();
        }

    }
}

Func<> is declared as public delegate TResult Func<out TResult>(); It encapsulates a method that has no parameters and returns a value of the type specified by the TResult parameter. In the MainWindow class, create an object of UISaveCommand class and assign the funcpointer to Save() method as shown below. So we are binding the method present in one class from other place using Command.

public partial class MainWindow : Window
{
    Student stobj = new Student();

   public MainWindow()
    {
        InitializeComponent();
        
        UISaveCommand savecommand = new UISaveCommand();
        savecommand.funcpointer = Save;
        stobj.StudentClassCommand = savecommand;
        this.DataContext = stobj;
    }

   public int Save()
   {
       MessageBox.Show(stobj.FirstName + stobj.LastName);
       return 0;
   }
}

Then we assign the savecommand object to the Student class property of type ICommand. Following is the code of the Student class.

public class Student : INotifyPropertyChanged
    {
       public ICommand StudentClassCommand
       {
           get;
           set;
       }

        private string firstname;

        public string FirstName
        {
            get { return firstname; }
            set
            {
                firstname = value;
                OnPropertyChanged("FirstName");
            }
        }

        private string lastname;

        public string LastName
        {
            get { return lastname; }
            set
            {
                lastname = value;
                OnPropertyChanged("LastName");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        
    }

The complete code of .CS file is

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.ComponentModel;

namespace CommandBinding2
{
    public class MyFirstCommand : ICommand
    {
        public void Execute(object parameter)
        {
            MessageBox.Show(parameter.ToString());
        }

        public bool CanExecute(object parameter)
        {
            if (parameter != null)
                return true;
            else
                return false;
        }
        public event EventHandler CanExecuteChanged;
    }

    public class UISaveCommand : ICommand
    {
        public Func<int> funcpointer
        {
            get;
            set;
        }

        public bool CanExecute(object parameter)
        {
            if (funcpointer != null)
            {
                return true;
            }
            else
                return false;

            throw new NotImplementedException();
        }

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        public void Execute(object parameter)
        {
            if (funcpointer != null)
            {
                funcpointer();
            }

        }
    }

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        Student stobj = new Student();

       public MainWindow()
        {
            InitializeComponent();
            
            UISaveCommand savecommand = new UISaveCommand();
            savecommand.funcpointer = Save;
            stobj.StudentClassCommand = savecommand;
            this.DataContext = stobj;
        }

       public UISaveCommand savecommand
       {
           get
           {
               throw new System.NotImplementedException();
           }
           set
           {
           }
       }

       public int Save()
       {
           MessageBox.Show(stobj.FirstName + stobj.LastName);
           return 0;
       }
    }

   public class Student : INotifyPropertyChanged
    {
       public ICommand StudentClassCommand
       {
           get;
           set;
       }

        private string firstname;

        public string FirstName
        {
            get { return firstname; }
            set
            {
                firstname = value;
                OnPropertyChanged("FirstName");
            }
        }

        private string lastname;

        public string LastName
        {
            get { return lastname; }
            set
            {
                lastname = value;
                OnPropertyChanged("LastName");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        
    }

    ////public class StringDelegateCommand : ICommand
    ////{
    ////    Action<string> m_ExecuteTargets = delegate { };
    ////    Func<bool> m_CanExecuteTargets = delegate { return false; };
    ////    bool m_Enabled = false;

    ////    public bool CanExecute(object parameter)
    ////    {
    ////        Delegate[] targets = m_CanExecuteTargets.GetInvocationList();
    ////        foreach (Func<bool> target in targets)
    ////        {
    ////            m_Enabled = false;
    ////            bool localenable = target.Invoke();
    ////            if (localenable)
    ////            {
    ////                m_Enabled = true;
    ////                break;
    ////            }
    ////        }
    ////        return m_Enabled;
    ////    }
        
    ////    public void Execute(object parameter)
    ////    {
    ////        if (m_Enabled)
    ////            m_ExecuteTargets(parameter != null ? parameter.ToString() : null);
    ////    }
        
    ////    public event EventHandler CanExecuteChanged = delegate { };

    ////    public event Action<string> ExecuteTargets
    ////    {
    ////        add { m_ExecuteTargets += value; }
    ////        remove { m_ExecuteTargets -= value; }
    ////    }

    ////    public event Func<bool> CanExecuteTargets
    ////    {
    ////        add { m_CanExecuteTargets += value; CanExecuteChanged(this, EventArgs.Empty); }
    ////        remove { m_CanExecuteTargets -= value; CanExecuteChanged(this, EventArgs.Empty); }
    ////    }
    ////}
}

 

The complete code of XAML file is

<Window x:Class="CommandBinding2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
        xmlns:local="clr-namespace:CommandBinding2"
        Title="MainWindow" Height="282" Width="474">
    <Grid Height="295" Width="440">
        <Grid.Resources>
            <local:MyFirstCommand x:Key="hwc"/>
        </Grid.Resources>

        <TextBlock Text="Enter First Name" Margin="0,0,271,261"></TextBlock>
        <TextBox Margin="175,6,12,260" Name="txtFirstName" VerticalAlignment="Center" Text="{Binding Path=FirstName}" Height="26" />
        <TextBlock Margin="0,48,324,216" VerticalAlignment="Center" Text="Enter Last Name" Height="28" />
        <TextBox Margin="175,55,12,215" Name="txtLastName" VerticalAlignment="Center" Text="{Binding Path=LastName}"/>
        <Button Margin="187,102,0,144" Content="Save"
                Command="{Binding StudentClassCommand}" />
        <Button Content="Hello World" Height="36" HorizontalAlignment="Left" Margin="12,115,0,0" Name="button1" VerticalAlignment="Top" Width="116"
                CommandParameter="Hello, World"
                Command="{StaticResource hwc}"/>
    </Grid>
</Window>

 

Attitude determines altitude. – Anonymous

Introduction to Command Binding

We have seen the abc’s of Data Binding here. If you have worked in VC++, then you are aware of some of the semantics of WPF command binding. Basically, commands are nothing but actions performed on the applications using input mechanism. commands are abstract and loosely-coupled version of events. Whereas events are tied to details about specific user actions (such as a Button being clicked or a List Item being selected), commands represent actions independent from their user interface exposure. Canonical examples of commands are Cut, Copy, and Paste. In VC++ MFC, we declare commands and then define the functions that execute the command action. Similarly, in WPF, the semantics and the object that invokes a command is separated from the logic that executes the command. This allows for multiple and disparate sources like MenuItems in a Menu, MenuItems on a Context Menu(Right Click), Buttons on a ToolBar, keyboard shortcuts(CTRL+X for Cut), and so on, to invoke the same command logic, and it allows the command logic to be customized for different targets. We used to perform similar design in VC++ too.

In VC++ MFC application, for example, the editing operations Copy, Cut, and Paste, can be invoked by using different user actions if they are implemented by using commands. An MFC application might allow a user to cut selected text by either choosing an Cut item in edit menu, or Cut in right click menu, or using a key combination, such as CTRL+X. By using commands, you can bind each type of user action to the same logic. In VC++, we assign ID’s to each command like ID_EDIT_COPY, ID_EDIT_CUT and ID_EDIT_PASTE. WPF supports similar concepts but uses a different mechanism to achieve it. By using commands, you can bind each type of user action to the same logic. Another purpose of commands is to indicate whether an action is available. To continue the example of cutting an object or text, the action only makes sense when something is selected. If a user tries to cut an object or text without having anything selected, nothing would happen. To indicate this to the user, many applications disable buttons and menu items so that the user knows whether it is possible to perform an action.

A command is any object implementing the ICommand interface (from System.Windows.Input), which defines two methods and one event:

  • Execute—The method that executes the command-specific logic
  • CanExecute—A method returning true if the command is enabled or false if it is disabled
  • CanExecuteChanged—An event that is raised whenever the value of CanExecute changes

Steps to create a Command:

  1. Say you want to create a Cut Command. We need to implement a class that implements ICommand.
  2. Call Execute from relevant event handlers (when CanExecute returns true)
  3. Handle the CanExecuteChanged event to toggle the IsEnabled property on the relevant pieces of user interface.

Fortunately, controls such as Button, CheckBox, and MenuItem have logic to interact with any command on your behalf. They expose a simple Command property (of type ICommand). When set, these controls automatically call the command’s Execute method (when CanExecute returns true) whenever their Click event is raised. In addition, they automatically keep their value for IsEnabled synchronized with the value of CanExecute by leveraging the CanExecuteChanged event. By supporting all this via a simple property assignment, all of this logic is available from XAML. Some of WPF’s controls have built-in behavior tied to various commands. 

WPF’s built-in commands like Cut, Copy, Paste are exposed as static properties and they are all instances of RoutedUICommand, a class that not only implements ICommand, but supports bubbling just like a routed event. A command can indicate whether an action is possible by implementing the CanExecute method. A button can subscribe to the CanExecuteChanged event and be disabled if CanExecute returns false or be enabled if CanExecute returns true.

WPF defines a bunch of commands already, so you don’t have to implement ICommand objects for Cut, Copy, and Paste and worry about where to store them. WPF’s built-in commands are exposed as static properties of five different classes:

  • ApplicationCommands—Close, Copy, Cut, Delete, Find, Help, New, Open, Paste, Print, PrintPreview, Properties, Redo, Replace, Save, SaveAs, SelectAll, Stop, Undo, and more
  • ComponentCommands—MoveDown, MoveLeft, MoveRight, MoveUp, ScrollByLine, ScrollPageDown, ScrollPageLeft, ScrollPageRight, ScrollPageUp, SelectToEnd, SelectToHome, SelectToPageDown, SelectToPageUp, and more
  • MediaCommands—ChannelDown, ChannelUp, DecreaseVolume, FastForward, IncreaseVolume, MuteVolume, NextTrack, Pause, Play, PreviousTrack, Record, Rewind, Select, Stop, and more
  • NavigationCommands—BrowseBack, BrowseForward, BrowseHome, BrowseStop, Favorites, FirstPage, GoToPage, LastPage, NextPage, PreviousPage, Refresh, Search, Zoom, and more
  • EditingCommands—AlignCenter, AlignJustify, AlignLeft, AlignRight, CorrectSpellingError, DecreaseFontSize, DecreaseIndentation, EnterLineBreak, EnterParagraphBreak, IgnoreSpellingError, IncreaseFontSize, IncreaseIndentation, MoveDownByLine, MoveDownByPage, MoveDownByParagraph, MoveLeftByCharacter, MoveLeftByWord, MoveRightByCharacter, MoveRightByWord, and more

Each of these properties does not return a unique type implementing ICommand. Instead, they are all instances of RoutedUICommand, a class that not only implements ICommand, but supports bubbling just like a routed event.

image

Lets develop a dialog that has a “Help” button, when clicked will open the help webpage. Let’s demonstrate how these built-in commands work by attaching some logic with the Help command defined in ApplicationCommands. Assuming the Button is named helpButton, you can associate it with the Help command in C# as follows:

helpButton.Command = ApplicationCommands.Help;

All RoutedUICommand objects define a Text property containing a name for the command that’s appropriate to show in a user interface. (This property is the only difference between RoutedUICommand and its base RoutedCommand class.) For example, the Help command’s Text property is (unsurprisingly) set to the string Help. The hard-coded Content on this Button could therefore be replaced as follows:

helpButton.Content = ApplicationCommands.Help.Text;

If you were to run the dialog with this change, you would see that the Button is now permanently disabled. That’s because the built-in commands can’t possibly know when they should be enabled or disabled, or even what action to take when they are executed. They delegate this logic to consumers of the commands. To plug in custom logic, you need to add a CommandBinding to the element that will execute the command or any parent element (thanks to the bubbling behavior of routed commands). All classes deriving from UIElement (and ContentElement) contain a CommandBindings collection that can hold one or more CommandBinding objects. Therefore, you can add a CommandBinding for Help to the dialog’s root Window as follows in

<Window.CommandBindings>
        <CommandBinding Command="Help"
                        CanExecute="CommandBinding_CanExecute"
                        Executed="CommandBinding_Executed" />
    </Window.CommandBindings>

 

Or in its code-behind file:

this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Help,
        CommandBinding_Executed, CommandBinding_CanExecute));

The methods called CommandBinding_Executed and CommandBinding_CanExecute have to be defined in code behind file as follows. These methods will be called back at appropriate times in order to plug in an implementation for the Help command’s CanExecute and Execute methods.

private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
    if (firstName.Text == "help")
        e.CanExecute = true;
    else
        e.CanExecute = false;

}

private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
    System.Diagnostics.Process.Start("https://kishore1021.wordpress.com/&quot;);

}

 

In the XAML file, assign the command to the help button as follows.

<Button Grid.Row="3" Grid.Column="1" Command="Help"
          Name="MyHelpButton" Margin="4,190,0,5">
            Help
        </Button>

 

Compile the project and run the application. Initially, the help button is disabled. Enter help in the first name textbox and you can see that the help button is enabled. Now to take advantage of command binding, say you want to bring up help when user presses keyboard shortcut F2 key. We can bind our own input gestures to a command by adding KeyBinding and/or MouseBinding objects to the relevant element’s InputBindings collection in code as follows

this.InputBindings.Add(
              new KeyBinding(ApplicationCommands.Help, new KeyGesture(Key.F2)));

The same binding can be performed in XAML as follows

<Window.InputBindings>
    <KeyBinding Command="Help" Key="F2"/>
    <KeyBinding Command="NotACommand" Key="F1"/>
</Window.InputBindings>

 

The complete XAML code is

<Window x:Class="CommandBinding101.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">
    <Window.CommandBindings>
        <CommandBinding Command="Help"
                        CanExecute="CommandBinding_CanExecute"
                        Executed="CommandBinding_Executed" />
    </Window.CommandBindings>
    <Window.InputBindings>
        <KeyBinding Command="Help" Key="F2"/>
        <KeyBinding Command="NotACommand" Key="F1"/>
    </Window.InputBindings>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="30"/>
            <RowDefinition Height="30"/>
            <RowDefinition Height="30"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>

        <Label>
            Enter your first name:
        </Label>
        <TextBox Grid.Row="0" Grid.Column="1"
           Name="firstName" Margin="0,5,10,5"/>

        <Label Grid.Row="1" >
            Enter your last name:
        </Label>
        <TextBox Grid.Row="1" Grid.Column="1"
           Name="lastName" Margin="0,5,10,5"/>

        <Button Grid.Row="2" Grid.Column="0"
          Name="Clear" Margin="2" Click="Clear_Click">
            Clear Name
        </Button>

        <Button Content="Enable Help" Margin="2" Name="button1" Grid.Column="1" Grid.Row="2" Click="button1_Click" />
        
        <Button Grid.Row="3" Grid.Column="1" Command="Help"
          Name="MyHelpButton" Margin="4,190,0,5">
            Help
        </Button>
        <Label Content="Type help in the first name edit box to enable the Help button" Margin="-1,13,12,164" Grid.Row="3" Grid.ColumnSpan="2" />
    </Grid>
    
</Window>

The complete code behind is

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 CommandBinding101
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            //MyHelpButton.Command = ApplicationCommands.Help;

           // this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Help,
           //  CommandBinding_Executed, CommandBinding_CanExecute));

            //this.InputBindings.Add(
            //  new KeyBinding(ApplicationCommands.Help, new KeyGesture(Key.F2)));

        }

        private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (firstName.Text == "help")
                e.CanExecute = true;
            else
                e.CanExecute = false;

        }

        private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            System.Diagnostics.Process.Start("https://kishore1021.wordpress.com/&quot;);

        }

        private void Clear_Click(object sender, RoutedEventArgs e)
        {
            firstName.Clear();
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            firstName.Text = "help";
        }
    }
}

If you use one of the preexisting RoutedUICommand objects for a WPF command, e.g. ApplicationCommands.Open, you’ll notice that the RoutedUICommand instance has a Text property.  This property in the command is used to set the label appearing on any MenuItem instances that have attached to the command by setting their Command property.  You don’t need to set the menu item’s Header property explicitly.

Download the source code here

If you really want the key to success, start by doing the opposite of what everyone else is doing.

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 Data Templates (DataTemplate with ListBox) –Part2

Download the source code from here.

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

DataTemplate is about the presentation of data and is one of the many features provided by the WPF styling and templating model.

To demonstrate why DataTemplate is important, let’s walk through a data binding example. In this example, we have a ListBox that is bound to a list of CustomError objects. Each Error object has a ErrorNumber(int), a ErrorDescription (string), a ErrorPriority (int), and a property of type ApplicationType, which is an Enum with values MR(Material Requisition),PO(Purchase Order) and Inventory.

public class CustomError
{
    public CustomError()
    {
    }

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

    public enum enumapplicationtype
    {
        MR,
        PO,
        Inventory
    };

    private int ErrorNumber;

    public int PropErrorNumber
    {
        get { return ErrorNumber; }
        set { ErrorNumber = value; }
    }
    private string ErrorDescription;

    public string PropErrorDescription
    {
        get { return ErrorDescription; }
        set { ErrorDescription = value; }
    }
    private int ErrorPriority;

    public int PropErrorPriority
    {
        get { return ErrorPriority; }
        set { ErrorPriority = value; }
    }
    private enumapplicationtype ErrorApplicationType;

    private enumapplicationtype PropApplicationType
    {
        get { return ErrorApplicationType; }
        set { ErrorApplicationType = value; }
    }
}

Let us create a collection of Error class as shown in the following code.

public class Errors : ObservableCollection<CustomError>
{
    public Errors() : base()
    {
        Add(new CustomError(1, "Error1", 1, CustomError.enumapplicationtype.MR));
        Add(new CustomError(2,"Error2",2,CustomError.enumapplicationtype.PO));
        Add(new CustomError(3, "Error3", 3, CustomError.enumapplicationtype.Inventory));
    }
}

Refer to the namespace in which the Errors class is present in XAML as shown below.

<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" Height="339" Width="333"
        xmlns:MyXAMLLocal="clr-namespace:Introduction_to_DataTemplates_2"
        >

Let us assign a static resource to the Errors observable collection in XAML as shown in the following code.

<StackPanel.Resources>
    <MyXAMLLocal:Errors x:Key="errorsobj"></MyXAMLLocal:Errors>
</StackPanel.Resources>

Let us bind the static resource that we created which is an object representation of the observable collection class Errors in XAML code as shown below.

    <Label Content="Errors List" FontSize="20"></Label>
    <ListBox Width="272" Margin="5" HorizontalAlignment="Stretch" ItemsSource="{Binding Source={StaticResource errorsobj}}" Height="232"></ListBox>
</StackPanel>

If we run the application; without a DataTemplate, our ListBox currently looks like this:

image

What’s happening is that without any specific instructions, the ListBox by default calls ToString when trying to display the objects in the collection. Therefore, if the Errors object overrides the ToString method, then the ListBox displays the string representation of each source object in the underlying collection.

For example, let us override the ToString method in Errors class as shown below.

public override string ToString()
{
    return ErrorNumber.ToString() + " "+ ErrorDescription + " "+ ErrorPriority.ToString() + " "+ ErrorApplicationType.ToString();
}

If we run the application, our ListBox currently looks like this:

image

However, that is limiting and inflexible. Also, if you are binding to XML data, you wouldn’t be able to override ToString. Most controls have some type of content, and that content often comes from data that you are binding to. In this example, the data is the error list . 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 the error information to appear in the listbox, you create a DataTemplate as shown below: We are giving instructions that each item appears as four TextBlock elements within a StackPanel. Each TextBlock element is bound to a property of the Error class. The underlying data is a collection of CLR objects.

<ListBox Width="272" Margin="5" HorizontalAlignment="Stretch"
         ItemsSource="{Binding Source={StaticResource errorsobj}}" Height="232">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <TextBlock Text="{Binding Path=PropErrorNumber}"></TextBlock>
                <TextBlock Text="{Binding Path=PropErrorDescription}"></TextBlock>
                <TextBlock Text="{Binding Path=PropErrorPriority}"></TextBlock>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

In the above code, we are setting the ItemTemplate property of the ListBox to a DataTemplate using inline mechanism.

It is more common to define it in the resources section so it can be a reusable object, which I will discuss in the next post.

The complete cs file code 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;

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

    public class CustomError
    {
        public CustomError()
        {
        }

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

        private int ErrorNumber;

        public int PropErrorNumber
        {
            get { return ErrorNumber; }
            set { ErrorNumber = value; }
        }
        private string ErrorDescription;

        public string PropErrorDescription
        {
            get { return ErrorDescription; }
            set { ErrorDescription = value; }
        }
        private int ErrorPriority;

        public int PropErrorPriority
        {
            get { return ErrorPriority; }
            set { ErrorPriority = value; }
        }
        private enumapplicationtype ErrorApplicationType;

        private enumapplicationtype PropApplicationType
        {
            get { return ErrorApplicationType; }
            set { ErrorApplicationType = value; }
        }
    }

    public class Errors : ObservableCollection<CustomError>
    {
        public Errors() : base()
        {
            Add(new CustomError(1, "Error1", 1, enumapplicationtype.MR));
            Add(new CustomError(2,"Error2",2,enumapplicationtype.PO));
            Add(new CustomError(3, "Error3", 3, enumapplicationtype.Inventory));
        }
    }

    public enum enumapplicationtype
    {
        MR,
        PO,
        Inventory
    }
}

The complete XAML code 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" Height="339" Width="333"
        xmlns:MyXAMLLocal="clr-namespace:Introduction_to_DataTemplates_2"
        >
    <StackPanel>
        <StackPanel.Resources>
            <MyXAMLLocal:Errors x:Key="errorsobj"></MyXAMLLocal:Errors>
        </StackPanel.Resources>
        <Label Content="Errors List" FontSize="20"></Label>
        <ListBox Width="272" Margin="5" HorizontalAlignment="Stretch"
                 ItemsSource="{Binding Source={StaticResource errorsobj}}" Height="232">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel>
                        <TextBlock Text="{Binding Path=PropErrorNumber}"></TextBlock>
                        <TextBlock Text="{Binding Path=PropErrorDescription}"></TextBlock>
                        <TextBlock Text="{Binding Path=PropErrorPriority}"></TextBlock>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </StackPanel>
</Window>

Download the source code from here.

 

Every great dream begins with a dreamer. Always remember, you have within you the strength, the patience, and the passion to reach for the stars to change the world. – Harriet Tubman

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