Monday, 9 September 2013

ControlTemplate in WPF

WPF controls are logically divided into their Appearance and Functionality.

Appearance defines look and feel of the control. Each WPF control has default control template that defines its appearance.

Functionality of the control is defined using methods, events and so on. Simple example of functionality is click event of button control.

Hence appearance of control can be customized by creating new ControlTemplate for control without affecting the functionality of the control.

In this post, we would customize Button control by creating a new ControlTemplate.

Let’s start by adding a simple Button control.

XAML

<Button Width="100" Height="100" FontSize="16" Content="Home" Name="btnHome" Click="btnHome_Click"></Button>

Code behind

private void Button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Home Button Clicked");
}

Output



What we see above is the output of default button control template.


 


Creating Inline ControlTemplate


Now we create an inline control template for Button control to change its appearance to circle.


XAML

<Button Width="100" Height="100" FontSize="16" Content="Home" Name="btnHome" Click="btnHome_Click">
<Button.Template>
<ControlTemplate>
<Grid>
<Ellipse Fill="LightBlue" Stroke="Blue"></Ellipse>
<TextBlock Text="Home" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
</Grid>
</ControlTemplate>
</Button.Template>
</Button>

Output


 


Important points are highlighted in yellow color in above code. Every Control has a Template property that is used to assign new control template to control. ControlTemplate is the class to create control template. Inside ControlTemplate, we have added a grid layout control with ellipse  and TextBlock containing text.


 


ControlTemplate defined as a resource


ControlTemplate created in above code is inline and hence applies to single button. To apply same template to multiple button controls, modify the code as below.


XAML

<Window x:Class="ControlTemplateSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="300" Width="300">
<Window.Resources>
<ControlTemplate x:Key="EllipseButton" TargetType="{x:Type Button}">
<Grid>
<Ellipse Fill="{TemplateBinding Property=Background}" Stroke="{TemplateBinding Property=BorderBrush}"></Ellipse>
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"></ContentPresenter>
</Grid>
</ControlTemplate>
</Window.Resources>
<StackPanel>
<Button Width="100" Height="100" FontSize="16" Content="Home" Name="btnHome" Margin="10" Click="btnHome_Click" Template ="{StaticResource ResourceKey=EllipseButton}" Background ="LightBlue" BorderBrush ="Blue">
</Button>
<Button Width="100" Height="100" FontSize="16" Content="About us" Name="btnAboutus" Margin="10" Click="btnAboutus_Click" Template ="{StaticResource ResourceKey=EllipseButton}" Background ="LightGreen" BorderBrush ="Green">
</Button>
</StackPanel>
</Window>

Output



What we have done here is added new ControlTemplate as a resource in resource dictionary, set its TargetType to Button and provide a unique key to the ControlTemplate. Then we apply new ControlTemplate to multiple button controls using Template property and StaticResource markup  extension.


 


TemplateBinding and ContentPresenter


If you have noticed same ControlTemplate is applied to both button controls, but their content, ellipse background and border color are different. If these values were set directly inside ControlTemplate, then they would have been same for all button controls which is not desired. Instead these values are actually derived from parent control to which template is applied. This is achieved using TemplateBinding.


TemplateBinding is a DataBinding Markup Extension that binds a property of a control inside ControlTemplate to the property of a templated control (Control to which this ControlTemplate is applied). This makes ControlTemplate flexible and reusable at different places.


TemplateBinding requires TargetType to be specified in ControlTemplate. TargetType=”{x:Type Button}” means this ControlTemplate is for Button control. If not specified, default TargetType is “Control” element which is base class for all WPF control.


If we do not specify TargetType and if we bind any property that is not present in “Control” class then compiler will throw error.


Ex: Consider below TextBlock added inside ControlTemplate

<TextBlock Text="{TemplateBinding Property=Content}"></TextBlock>

Here we bind Text property of TextBlock to Content property of templated control. If TargetType is not specified on ControlTemplate, then compiler takes default “TargetType” as Control. Now Content property is used in TemplateBinding but not present in Control class so Compiler with throw compile time error saying: “Cannot find the static member 'ContentProperty' on the type 'Control”.


ContentPresenter is the place holder for the content property of element and will be replaced by the actual content from the templated parent control at run time. ContentPresenter internally uses TemplateBinding and requires TargetType to be set. If we remove TargetType from ControlTemplate, then compile will not throw error but at runtime content would not be displayed. This is the mistake that sometimes people make and finds it difficult to debug.


Different between TemplateBinding & ContentPresenter


TemplateBinding is a DataBinding Markup Extension that can be used to bind any property of a control inside ControlTemplate to template control property of same type. While ContentPresenter is actually a Place Holder for Content Property of template control.


 


 Triggers


After creating a new ControlTemplate and running the application, we noticed that when we move mouse over the Button, there is no effect. Default button control template changes button background with some sort of blue gradient. Trigger would be useful to achieve this. ControlTemplate allows defining Trigger that can be used to change appearance of controls based on some user interaction.


XAML

<ControlTemplate x:Key="EllipseButton" TargetType="{x:Type Button}">
<Grid>
<Ellipse Name="ellipse" Fill="{TemplateBinding Property=Background}" Stroke="{TemplateBinding Property=BorderBrush}"></Ellipse>
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"></ContentPresenter>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property ="IsMouseOver" Value ="True">
<Setter TargetName ="ellipse" Property ="Fill" Value ="Goldenrod"></Setter>
<Setter TargetName ="ellipse" Property ="Stroke" Value ="Brown"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>

Output



Here we have given name to ellipse control so that ellipse can be used in Trigger section. When user moves mouse over Button control, we set Fill and stroke property of ellipse control to different values.


 


Additional information


While understanding TemplateBinding and ContentPresenter I explored 2 other ways in which we can derive values from parent/templated control. So I am mentioning them here. This is just for sake of knowledge and understanding. Mainly prefer to use TemplateBinding and ContentPresenter inside ControlTemplate.


Consider a TextBlock inside ControlTemplate. Text property of this TextBlock control should be derived from Content property of templated control. We can use RelativeResource DataBinding.



1.  RelativeResource - RelativeResource is a DataBinding markup extension that is used to reference a resource/control that is positioned relatively to current control.


<TextBlock Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Button}, Path=Content}"></TextBlock>


In above code, Binding will search for Ancestor control of Type Button up in the hierarchy and set the value of Content property of Button control to Text property of TextBlock control.


This syntax is not specific to templates. This is generic way of finding any control up in the hierarchy and binding its properties. Below is more template specific syntax.


2. TemplatedParent - RelativeResource provides Mode property which can be set to TemplatedParent. This means search for parent control to which this template is applied.

<TextBlock Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Content}"></TextBlock>


TemplateBinding can be thought as an optimization to above TemplatedParent syntax and provides easier, better and preferred way of binding property of parent control.

Sunday, 1 September 2013

C# Delegates Series Part 4 - Delegates can be used to Invoke methods asynchronously

Below is the reference of all posts in this series

  1. C# Delegates Series Part 1 - Overview
  2. C# Delegates Series Part 2 - Delegates allows methods to be passed as parameters
  3. C# Delegates Series Part 3 - Delegates can be used to define event handlers and event handling mechanism
  4. C# Delegates Series Part 4 - Delegates can be used to Invoke methods asynchronously

When Main UI thread invokes some method, main thread waits until that method completes and then continues with rest of the processing. This might turn out expensive in some scenarios where called method takes more time to execute or communicates with third party service or downloads a large file. This would make application less responsive. In such cases, delegates can be useful to call these methods asynchronously.

Note: BackgroundWorker class in C# is another powerful way to execute code asynchronously. BackgroundWorker also supports reporting progress, cancelling the thread and so on.

There are 4 different ways to invoke methods asynchronously using delegates with some variations.

1.   Call a Method Asynchronously using Delegate BeginInvoke and EndInvoke: In this approach, main thread will invoke other method using delegate BeginInvoke method. BeginInvoke initiates asynchronous call on separate thread and returns immediately so that main thread can continue with rest of the processing. Main thread can later call EndInvoke method to end the thread and return the result. If main thread has call EndInvoke and if method has not completed the execution, then main thread will wait for method to complete.

2.   Call a Method Asynchronously using WaitHandle: In this approach, the main thread will invoke other method using delegate BeginInvoke method, waits for a WaitHandle and then call EndInvoke().

3.   Call a Method Asynchronously in .NET using Polling: In this approach, Main thread will invoke other method using delegate BeginInvoke, continue with rest of the processing and periodically poll other thread/method (using IAsyncResult IsCompleted property) to check if method has completed the execution. During polling, if main thread finds that method has completed the execution (IsCompleted = true), delegate EndInvoke will be used to end the thread and return the result from method.

4.   Call a Method Asynchronously in .NET using Callback: In this approach, main thread will invoke other method using delegate BeginInvoke along with callback method passed as parameter and continue with rest processing. When other method completes the execution, it invokes callback method which is passed as delegate reference. This callback method will then call delegate EndInvoke to end the thread and return the result from method.

MSDN article provides a good description of these approaches along with examples.

C# Delegates Series Part 1 - Overview

At times, I have come across people who understand some basics of delegates but are really confused on when should they use delegates and how delegates are useful. During course of my development, I came across several scenarios where delegates were quite useful in achieving the desired functionality. So here is a series of delegates that would help you understand basic concepts of delegates and some scenarios  where delegates are useful.

  1. C# Delegates Series Part 1 - Overview
  2. C# Delegates Series Part 2 - Delegates allows methods to be passed as parameters
  3. C# Delegates Series Part 3 - Delegates can be used to define event handlers and event handling mechanism
  4. C# Delegates Series Part 4 - Delegates can be used to Invoke methods asynchronously

 

Let’s start with Overview of delegates

Delegates are similar to function pointers in C, C++. Delegates holds reference to function/method of same signature. When delegates are invoked, they in-turn invoke the function that is referenced. At first glance, it might seem difficult to understand why we need delegate and why can’t we call functions directly. Thinking of single class/file, it might not make much sense. But delegates starts getting useful when they span across multiple classes, multiple components, implementing event handles, callbacks, invoking functions asynchronously and so on. Don’t worry we would understands these scenarios in details as the article follows.

Let’s first understand steps involved in creating and using a simple delegate.

1.  Declaring delegate: A Delegate is a type that define method signature.

public delegate int MathDelegate(int a, int b);


2.  Creating method: Method that should be invoked when delegate is used.

public int Add(int a, int b)
{
return a + b;
}

public int Subtract(int num1, int num2)
{
return num1 - num2;
}

Here we define 2 methods that have same signature as delegate (return type, number of parameters and type of parameters).


Simply remove delegate keyword in step - 1 and replace MathDelegate with Add and this becomes our Add method signature.


It is not compulsory to match names of parameters. Check Subtract method where I have changed parameter name a with num1 and parameter name b with num2.


3.  Instantiate delegate: Create an instance of delegate and pass the function as parameter.

MathDelegate addDelegate = new MathDelegate(Add);
MathDelegate subtractDelegate = new MathDelegate(Subtract);

4.  Use delegate:

int result = addDelegate(10, 5);
MessageBox.Show(result.ToString());

result = subtractDelegate(10, 5);
MessageBox.Show(result.ToString());


Here, calling the delegate would invoke function that is referenced and return the result.



Now as we know what a delegate means, let’s understand some facts and real examples of delegate in next sequence of articles.

C# Delegates Series Part 3 - Delegates can be used to define event handlers and provide event handling mechanism

Below is the reference of all posts in this series

  1. C# Delegates Series Part 1 - Overview
  2. C# Delegates Series Part 2 - Delegates allows methods to be passed as parameters
  3. C# Delegates Series Part 3 - Delegates can be used to define event handlers and event handling mechanism
  4. C# Delegates Series Part 4 - Delegates can be used to Invoke methods asynchronously

Delegates are the base for Event handling mechanism in .net framework. Consider an example of Button Click event. Let’s see below code.

C# - Windows Forms

public Form1()
{
InitializeComponent();
btnSave.Click += btnSave_Click;
}

private void btnSave_Click(object sender, EventArgs e)
{

}

WPF

public MainWindow()
{
InitializeComponent();
btnSave.Click += btnSave_Click;
}

private void btnSave_Click(object sender, RoutedEventArgs e)
{

}

Here Click is the event of Button. btnSave_Click is the event handler/method that will be executed when button is clicked. Above syntax is called wiring event with event handler/method.


Now if we see the definition of button Click event  (Place cursor over Click keyword and Press F12 or right click on Click keyword and select go to definition), we find below code.


C# – Windows forms

public event EventHandler Click;

Drill down further to definition of EventHandler and we see below.

public delegate void EventHandler(object sender, EventArgs e);

So EventHandler is of type delegate that takes 2 arguments and returns nothing. Now if we see our definition of BtnSave method this would match with signature of delegate.


WPF

public event RoutedEventHandler Click;

Drill down further to definition of RoutedEventHandler and we see below.

public delegate void RoutedEventHandler(object sender, RoutedEventArgs e);

So RoutedEventHandler is of type delegate that takes 2 arguments and returns nothing. Now if we see our definition of BtnSave method this would match with signature of delegate.


That’s all about .net framework, now we see a real life example where we would find this useful.


There can be several examples.


Suppose you are designing a Login UserControl that takes login information from User. When user click OK button, you want en event to be fired on parent control (hosting Login UserControl) for further/additional processing.


In this post, we extend an example of our previous post where we created a Form that displays list of Assets. When user selects an Asset and clicks OK button, an event is fired in parent control (control that opened this Assets form) and selected asset information is passed to parent control.


Below is the code to achieve this functionality using delegates and events. In this post, we take an example of WPF application. Download the attached sample for complete example in C# console application, Windows forms and WPF.


Assets.xaml.cs


Assets page will load and displays list of assets in DataGrid. When user selects an asset in DataGrid and clicks OK button, an event should be fired in calling window that invoked Assets window. To achieve this we declare a delegate that can hold reference to method with one argument and returns no value. Then we create an event based on this delegate.

// Declare delegate
public delegate void AssetSelectedEventHandler(AssetItem item);

// Create event based on delegate
public event AssetSelectedEventHandler AssetSelected;

When user clicks OK button, we check if parent control (MainWindow in this case) has subscribed to this event by comparing AssetSelected to null and then we raise the AssetSelected event with argument as selected asset.

private void btnOK_Click(object sender, RoutedEventArgs e)
{
if (AssetSelected != null)
AssetSelected((AssetItem)AssetsGrid.SelectedItem);

this.Close();
}

MainWindow.xaml.cs


This is the main window that is displayed when application is started. In MainWindow, we load Assets.xaml window.

Assets assetSelector = new Assets(FilterMethod);
assetSelector.Owner = this;
assetSelector.AssetSelected += assetSelector_AssetSelected;
assetSelector.ShowDialog();
private void assetSelector_AssetSelected(AssetItem item)
{
// Here we get selected AssetItem information.
}

Code highlighted in yellow shows that “AssetSelected” event defined in Assets.xaml is attached to the event handler “assetSelector_AssetSelected”. Hence when AssetSelected event is raised in Assets.xaml window, assetSelector_AssetSelected event handler is called in MainWindown.xaml

C# Delegates Series Part 2 - Delegates allows methods to be passed as parameters

Below is the reference of all posts in this series

  1. C# Delegates Series Part 1 - Overview
  2. C# Delegates Series Part 2 - Delegates allows methods to be passed as parameters
  3. C# Delegates Series Part 3 - Delegates can be used to define event handlers and event handling mechanism
  4. C# Delegates Series Part 4 - Delegates can be used to Invoke methods asynchronously

In part 1, we understood brief overview of delegates and how to create/use delegates. In this post we will look at how delegates can be used to pass methods as parameters and how would this be useful in real scenario.

We are used to passing properties as parameters to methods in same or different class/forms. But what about passing methods as parameters to other method/class. Is that really useful? If yes, how can we do that? Answer lies below.

Suppose you are asked to develop a component that loads all objects (ex assets) from database and display to user for selection. This component will be reused and called from multiple application.

Now you are asked to design the component to be flexible such that business/filter logic to decide weather an object (asset) to display or not should reside in consuming application (and not in the component) and can vary from application to application.

Ex: One client application can define filter criteria to load only those items (assets) that are of Category "X". Where as other client application can define filter criteria to load only those items (assets) that belong to Location "X". Consuming application should be able to define its own filter criteria without any change required in the component.

Design for creating such component would require that component would fetch all assets from database, and then for each item call some function in consuming application that has filtering logic to check if asset needs to be displayed or not and returns Boolean value. This is one such scenario where delegates can be extremely useful.

Now if you think of methods like FindAll, Select on generic List in C#, this would start making some sense. Internally these methods use delegates.

Let’s take an example of how you would achieve such functionality using delegate. To keep this language neutral, we take 3 simple class and use simple pseudo code. Download the attached sample for complete example in plain C#, Windows forms and WPF.

AssetItem.cs

public class AssetItem
{
public string ID { get; set; }
public string Name { get; set; }
public string Location { get; set; }
public string Category { get; set; }
}

AssetSelector.cs (Component part)

public class AssetSelector
{
// Declaring delegate
public delegate bool FilterDelegate(AssetItem item);

public FilterDelegate FilterMethod;

public AssetSelector(FilterDelegate filterMethod)
{
// Create an instance of delegate and assign client side method passed as parameter.
FilterMethod = new FilterDelegate(filterMethod);
}

public void LoadAssets()
{
// Load all assets from database.
List<AssetItem> Assets = GetAssets();

List<AssetItem> filteredAssets = new List<AssetItem>();
foreach (AssetItem item in Assets)
{
// Using delegate to invoke client side filter method passed as reference.
if (FilterMethod(item))
filteredAssets.Add(item);

}

// Bind data grid with filteredAssets;
}

private static List<AssetItem> GetAssets()
{
List<AssetItem> Assets = new List<AssetItem>();
return Assets;
}
}

Client.cs (Consuming application part)

public class Client
{
public void SelectAssets()
{
AssetSelector selector = new AssetSelector(FilterMethod);

// Pass "FilterMethod" method as parameter.
selector.LoadAssets();
}

// Declare method that matches delegate signature and contains filtering logic.
public bool FilterMethod(AssetItem item)
{
if (item.Category == "Electronics")
return true;
else
return false;
}
}

 


Implementing callbacks with delegates


If you understand the above concept of using delegates, then implementing callbacks would be similar and easy task for you. Steps remains the same.



Parent/Client class would create a CallbackMethod and pass this method as an argument when calling the component/another class.


Component class would create the delegate with same method signature, store the reference of CallbackMethod in delegate and task is completed use the delegate to invoke CallbackMethod.


Callback makes more sense when you are designing a component that performs a some task asynchronously or uses API/third party service that provides response asynchronously. In this case client application would call the component to perform the task and continue with other operations instead of waiting for the component to return the result. This makes client application responsive. Once component has completed the task, component use the delegate to provide callback to the client application.

Sunday, 28 July 2013

WPF - Achieve same functionality using IValueConverter and Trigger

Sample Code for Download

WPF is quite flexible and powerful in nature. WPF provides variety of features that can be used to achieve the desired functionality easily. Let me  show an example where same functionality can be achieved using different ways. There are several such examples that we would come across while using WPF, I am sharing just one of them here.

Functionality we try to achieve is as follows

When Checkbox is in Checked state, show details panel

When Checkbox is in Unchecked state, hide details panel.

For this functionality, we use a Checkbox and a StackPanel containing details.

Output

     

Approach 1. Using IValueConverter

<Window x:Class="WPFMultipleOptions.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter"></BooleanToVisibilityConverter>
</Window.Resources>
<StackPanel Orientation="Vertical" Margin="10">

<CheckBox Name="chkShowDetails" Content="Show Details - using Converter" Margin="0 10 0 0">
</CheckBox>

<StackPanel Name="spDetails" Margin="0 10 0 0" Visibility ="{Binding ElementName=chkShowDetails, Path=IsChecked, Converter={StaticResource ResourceKey=BoolToVisibilityConverter}}">
<Border BorderBrush="Black" BorderThickness="1" CornerRadius="10" Padding="10">
<StackPanel Orientation="Vertical">
<TextBlock Text="Details Here"></TextBlock>
<TextBlock Text="Details Here"></TextBlock>
<TextBlock Text="Details Here"></TextBlock>
<TextBlock Text="Details Here"></TextBlock>
<TextBlock Text="Details Here"></TextBlock>
</StackPanel>
</Border>
</StackPanel>
</StackPanel>
</Window>

In above code, we have used Element to Element binding. StackPanel Visibility property is bound to CheckBox IsChecked property.


But Visibility property is of type enum and expects one of these values: Visible, Hidden or Collapsed. While CheckBox IsChecked property returns True or False.


So we use built-in BooleanToVisibilityConverter that converts takes Boolean value as input and returns Visibility value as output.


Approach 2. Using Trigger


Now same functionality can also be achieved using triggers. Let’s see how.

<Window x:Class="MultipleOptions.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel Orientation="Vertical" Margin="10">

<CheckBox Name="chkShowDetailsUsingTrigger" Content="Show Details - using trigger" Margin="0 10 0 0">
</CheckBox>

<StackPanel Name="spDetailsUsingTrigger" Margin="0 10 0 0">
<Border BorderBrush="Black" BorderThickness="1" CornerRadius="10" Padding="10">
<StackPanel Orientation="Vertical">
<TextBlock Text="Details Here"></TextBlock>
<TextBlock Text="Details Here"></TextBlock>
<TextBlock Text="Details Here"></TextBlock>
<TextBlock Text="Details Here"></TextBlock>
<TextBlock Text="Details Here"></TextBlock>
</StackPanel>
</Border>
<StackPanel.Style>
<Style TargetType="StackPanel">
<Setter Property="Visibility" Value="Hidden"></Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=chkShowDetailsUsingTrigger, Path=IsChecked}" Value="True">
<Setter Property="Visibility" Value="Visible"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>

</StackPanel>
</StackPanel>
</Window>

In above code, by default we have set visibility of StackPanel (details section) to false. Then we have added DataTrigger on StackPanel. DataTrigger Binding is set to CheckBox IsChecked property. If value is True then Setter gets executed and sets Visibility of StackPanel to true.

Monday, 13 May 2013

Data Binding XAML control to property in code behind

Sample code this article

Binding to property defined in code behind

using System.Windows;

namespace WPFDataBindingCodeBehind
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private string _helloText = "Hello World";
public string HelloText
{
get { return _helloText; }
set { _helloText = value; }
}

public MainWindow()
{
InitializeComponent();
}
}
}

One important point to note in code behind above is that _helloText string has been assigned value at the time of Declaration. Hence when controls are loaded and binding happens, this value is already available and displayed. Below we would see what happens when we change value in Window Load event and how to handle that.


1. Binding using RelativeResource

<TextBlock Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}, Path=HelloText}"></TextBlock>

2. Binding using ElementName


Here we are using Element to Element Binding syntax. Name of Window is set to “myWindow”. Then Text property binds to “HelloText” property in element “myWindow”.

<Window x:Class="WPFDataBindingCodeBehind.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Name="myWindow"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<TextBlock Text="{Binding ElementName=myWindow, Path=HelloText}"></TextBlock>
</StackPanel>
</Window>

3. Binding using DataContext of Window set to Self


Here DataContext of entire window is set to code behind. All controls in this window would inherit this DataContext and hence their source for data binding would become code behind. So all controls can directly bind to properties.

<Window x:Class="WPFDataBindingCodeBehind.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}">
<StackPanel>
<TextBlock Text="{Binding Path=HelloText}"></TextBlock>
</StackPanel>
</Window>

4. Binding using DataContext of Parent element set to Window



Instead of setting DataContext of entire window to code behind, this syntax would set DataContext of parent StackPanel to code behind. Syntax for setting DataContext is similar to syntax is method 1.

<Window x:Class="WPFDataBindingCodeBehind.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}">
<TextBlock Text="{Binding Path=HelloText}"></TextBlock>
</StackPanel>
</Window>

Important Note


Now, If we change the value in Window Load event then this changes would not be reflected. TextBlock will still display “Hello World” string. This is because when controls are loaded in InitializeComponent(), binding happens for first time and value is set to “Hello World”.

<Window x:Class="WPFDataBindingCodeBehind.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
using System.Windows;
using System.ComponentModel;

namespace WPFDataBindingCodeBehind
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private string _helloText = "Hello World";
public string HelloText
{
get { return _helloText; }
set { _helloText = value; }
}

public MainWindow()
{
InitializeComponent();
}

private void Window_Loaded(object sender, RoutedEventArgs e)
{
HelloText = "Value Changed";
}

}
}

Implementing INotifyPropertyChanged


Once binding happens, any changes to the source value needs to be notified to the target control so that control can update the binding value. To achieve this, WPF provides INotifyPropertyChanged mechanism.

using System.Windows;
using System.ComponentModel;

namespace WPFDataBindingCodeBehind
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
private string _helloText = "Hello World";
public string HelloText
{
get { return _helloText; }
set { _helloText = value; }
}

public MainWindow()
{
InitializeComponent();
}

private void Window_Loaded(object sender, RoutedEventArgs e)
{
HelloText = "Value Changed";
RaisePropertyChanged("HelloText");

}


public event PropertyChangedEventHandler PropertyChanged;

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

Binding Collections


Collection can be bound same way as property above. We have declared an ObservableCollection<string> named “myString” and instantiated at the time of declaration. This string is then bound to ListBox. ObservableCollection is a specialized type of List which provides built-in implementation of INotifyPropertyChanged and hence when any items are added/removed from the collection, same is notified to the target control.


XAML

<Window x:Class="WPFDataBindingCodeBehind.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Name="myWindow"
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
<StackPanel>
<ListBox ItemsSource="{Binding ElementName=myWindow, Path=MyStrings}"></ListBox>
</StackPanel>
</Window>

Code Behind

using System.Windows;
using System.ComponentModel;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace WPFDataBindingCodeBehind
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private ObservableCollection<string> myStrings = new ObservableCollection<string>();
public ObservableCollection<string> MyStrings
{
get { return myStrings; }
set { myStrings = value; }
}

public MainWindow()
{
InitializeComponent();
}

private void Window_Loaded(object sender, RoutedEventArgs e)
{
MyStrings.Add("Apple");
MyStrings.Add("Oranges");
MyStrings.Add("Mango");
MyStrings.Add("Banana");
MyStrings.Add("Watermelon");
}
}
}

Saturday, 4 May 2013

Markup Extension in WPF

Download Code – Sample containing all Markup Extensions

Markup Extension is very useful and handy feature in XAML.

Instead of directly specifying string values for properties in XAML, Markup extension can be used to provide values to properties that can be retrieved from different sources.

Let’s take a simple example of setting Background color of TextBlock.

Directly specify string value for Background property

<TextBlock Background="LightBlue"></TextBlock>

Using Markup Extension


We will use StaticResource Markup Extension to set Background property value. StaticResource means referring to a resource defined in XAML. So we define a resource for LightBlue color.

<Window.Resources>
<SolidColorBrush x:Key="LightBlueColor" Color="LightBlue"></SolidColorBrush>
</Window.Resources>

Now, Markup Extension can be set using Attribute syntax or Property Element Syntax.


Attribute syntax: This syntax is used in most of the cases when using Markup Extension. Syntax uses opening and closing curly braces ( { } ). Type of Markup Extension to be used is identified through string immediately after opening curly braces.

<TextBlock Background="{StaticResource ResourceKey=LightBlueColor}"></TextBlock>

Here, StaticResource string after opening curly braces indicates XAML parser to use StaticResource Markup Extension. StaticResource has a ResourceKey property which should be set to the key value of resource to be used. StaticResource extension would internally use this ResourceKey to lookup and return the resource.


Property Element syntax: Syntax is similar to using any other element using angle brackets ( <> )

<TextBlock>
<TextBlock.Background>
<StaticResource ResourceKey="LightBlueColor"></StaticResource>
</TextBlock.Background>
</TextBlock>

You might not get StaticResource in intellisense when using property Element syntax but it compiles and works fine.


Markup Extension is simple and easy to use but adds lots of power and flexibility to programming language. Once you start exploring different built-in Markup Extension provided in WPF you will start realizing that.


Types of Markup Extension


WPF provides several built-in Markup extensions which can be broadly classified into 2 categories.



XAML Defined - Markup Extension that are defined as an intrinsic feature of XAML as a language. Note: XAML language is also used for creating UI in other platforms like Silverlight, Windows Phone, Windows 8 etc. These extension are present in XAML namespace and accessed using default “x:” prefix.


WPF Specific - Markup Extension that are specific to WPF.


Below chart provides a quick overview of different Markup Extensions and their short description.


WPF MarkupExtension


I have added all Markup Extensions in sample attached at the top of this post. I have also posted code snippets in separate post here.


Here is a nice MSDN link which has links to different Markup Extension.


In next post, we will look at creating custom Markup Extension.

WPF Markup Extension Sample Code Snippets

In last post, we have seen an brief overview of Markup Extension and different types of Markup Extensions.

I thought it would be useful to create a sample that uses all Markup Extensions. You can download the sample: Download Code – Sample containing all Markup Extensions

Also I am posting code snippets for all Markup Extension for quick reference.

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 WPFMarkupExtension
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private string simpleText = "Text set using Binding Markup Extension";
public string SimpleText
{
get { return simpleText; }
set { simpleText = value; }
}

private string firstName = "Text set using";
public string FirstName
{
get { return firstName; }
set { firstName = value; }
}

private string lastName = "MultiBinding Markup Extension";
public string LastName
{
get { return lastName; }
set { lastName = value; }
}

//private string bindingValue1 = "first binding";
//public string BindingValue1
//{
// get
// {
// throw new ApplicationException();
// return bindingValue1;
// }
//}

private string bindingValue2 = "Second binding returned value successfully";
public string BindingValue2
{
get { return bindingValue2; }
set { bindingValue2 = value; }
}

public static string StaticField = "Text set using Static Markup Extension";

public MainWindow()
{
InitializeComponent();
}
}
}

 

<Window x:Class="WPFMarkupExtension.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WPFMarkupExtension"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="MainWindow" Height="600" Width="600">
<Window.Resources>
<SolidColorBrush x:Key="LightBlueColor" Color="LightBlue"></SolidColorBrush>
<local:MyConverter x:Key="myConverter"></local:MyConverter>

<!--Usage of x:Array Marukup Extension-->
<x:ArrayExtension x:Key="fruits" Type="sys:String">
<sys:String>Apple</sys:String>
<sys:String>Orage</sys:String>
<sys:String>Mango</sys:String>
<sys:String>Banana</sys:String>
</x:ArrayExtension>

<!--Usage of x:Type Maukup Extension-->
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Margin" Value="5"></Setter>
<Setter Property="Padding" Value="5"></Setter>
</Style>

<!--Usage of TemplateBinding Markup Extension-->
<ControlTemplate x:Key="EllipseButton" TargetType="{x:Type Button}">
<Grid>
<!--TemplateBinding is used to set property of control in ControlTemplate to property of
parent control to which this template is applied.-->
<!--Instead of specifying hard code value for Fill property, we inherit property from
parent control. This adds flexibility to template.-->
<Ellipse Fill="{TemplateBinding Background}"></Ellipse>
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"></ContentPresenter>
</Grid>
</ControlTemplate>
</Window.Resources>
<StackPanel>

<GroupBox Header="XAML Defined">
<StackPanel>
<!--Usage of x:Null Markup Extension-->
<!--Style defined for TextBlock in Window.Resources section applies to all TextBlock.
We want this particular TextBlock not to use that style. So we set Style to Null-->
<TextBlock Style="{x:Null}" Text="Null Markup extension usage"></TextBlock>

<!--Usage of x:Static Markup Extension-->
<!--local refers to namespace of current project which is imported in Window element at top
MainWindow refers directly to Class (and not instance of Class)
StaticField is static property in MainWindow class-->
<TextBlock Text="{x:Static Member=local:MainWindow.StaticField}"></TextBlock>
</StackPanel>
</GroupBox>

<GroupBox Header="WPF Specific">
<!--Usage of RelativeResource Markup Extension-->
<!--DataContext for StackPanel is set to current window (means code behind).
Hence all controls in this StackPanel will inherit this DataContext as source for binding.-->
<StackPanel DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}">
<TextBlock Background="LightBlue"
Text="Background property set using direct string vlaue"></TextBlock>

<!--Usage of StaticResource Markup Extension (Attribute Syntax) -->
<TextBlock Background="{StaticResource ResourceKey=LightBlueColor}"
Text="Background property set using StaticResource Markup Extension - Attribute Syntax"></TextBlock>

<!--Usage of StaticResource Markup Extension (Property Element Syntax) -->
<TextBlock Text="Background property set using StaticResource Markup Extension - Property Element Syntax">
<TextBlock.Background>
<StaticResource ResourceKey="LightBlueColor"></StaticResource>
</TextBlock.Background>
</TextBlock>

<!--Usage of DynamicResource Markup Extension (Attribute Syntax) -->
<TextBlock Background="{DynamicResource ResourceKey=LightBlueColor}"
Text="Background property set using DynamicResource Markup Extension"></TextBlock>

<!--Usage of Binding Markup Extension (Attribute Syntax) -->
<TextBlock Text="{Binding SimpleText}"></TextBlock>

<!--Usage of Binding Markup Extension (Property Element Syntax) -->
<TextBlock>
<TextBlock.Text>
<Binding Path="SimpleText"></Binding>
</TextBlock.Text>
</TextBlock>

<!--Usage of MultiBinding Markup Extension-->
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} {1}">
<!--StringFormat is can be used for simple string concat/manipulation.
For complex requirements ValueConverter can be used as commented below-->
<!--<MultiBinding Converter="{StaticResource ResourceKey=myConverter}"
StringFormat="{}{0} {1}">-->
<Binding Path="FirstName"></Binding>
<Binding Path="LastName"></Binding>
</MultiBinding>
</TextBlock.Text>
</TextBlock>

<!--Usage of StaticResource Markup Extension-->
<ListBox ItemsSource="{StaticResource ResourceKey=fruits}"></ListBox>

<!--Usage of PriorityBinding Markup Extension-->
<TextBlock HorizontalAlignment="Left">
<TextBlock.Text>
<!--PriorityBinding can be used for sharing same data template with multiple
controls or for showing progress in async operations.-->
<PriorityBinding>
<!-- // First Binding is not present or binding throws exception
or does not return some value then Second Binding is used -->
<Binding Path="BindingValue1"></Binding>
<Binding Path="BindingValue2"></Binding>
</PriorityBinding>
</TextBlock.Text>
</TextBlock>

<!--Usage of TemplateBinding Markup Extension-->
<!--See EllipseButton ControlTemplate-->
<Button Width="150" Height="75" Content="TemplateBinding usage" HorizontalAlignment="Left"
Background="LightBlue" Template="{StaticResource ResourceKey=EllipseButton}">
</Button>
</StackPanel>
</GroupBox>
</StackPanel>
</Window>