Anup Shah on WPF and Silverlight (Programming Garden)

IT 's For You!!!

Wednesday, November 23, 2011

Saturday, November 19, 2011

WPF and Silverlight Layout Controls

The WPF and Silverlight platforms have a wide selection of powerful layout controls. This topic will provide you with an understanding of these layout controls and how to take advantage of the WPF and Silverlight Designer features when working with these controls. In this topic when the term pixel is used, it refers to a device-independent-pixel. In WPF a pixel is 1/96 of an inch. This MSDN topic covers device-independent-pixels. http://msdn.microsoft.com/en-us/library/bb847924.aspx

Table of Contents


  1. Layout Control Types
  2. Panel Selection
  3. Panels
  4. Grid
  5. StackPanel
  6. Canvas
  7. DockPanel
  8. WrapPanel
  9. UniformGrid
  10. Panel.ZIndex
  11. Decorators
  12. Border
  13. Content Controls
  14. Window
  15. UserControl
  16. GroupBox
  17. Expander
  18. TabItem
  19. Items Controls
  20. TabControl
  21. Layout Properties
  22. Comments

Layout Control Types

WPF layout controls can be logically grouped by base types that determine their behavior.

  1. Panels

    1. Provide arrangement of their child objects.
    2. Derive directly or indirectly from Panel.
    3. Have a Children property that is a collection of their child objects.
    4. Example controls are the Grid, StackPanel, Canvas, DockPanel WrapPanel and UniformGrid.
  2. Decorators

    1. Apply effects to their single child object.
    2. Derive from Decorator.
    3. Have a Child property that contains their single child object.
    4. Example controls are the Border and ViewBox
  3. Content Controls

    1. Contain a single object of any type.
    2. Derive directly or indirectly from ContentControl.
    3. Have a Content property that contains their single object.
    4. Example controls are the Window, UserControl, GroupBox, TabItem, Expander, HeaderedContentControl and ContentControl.
  4. Items Controls

    1. Used to present a collection of objects.
    2. Derive directly or indirectly from ItemsControl.
    3. Have two ways of being populated

      • Objects can be added to the Items property in code behind or in XAML.
      • A list of objects can be bound to the ItemsSource property.
    4. When objects are added using either of the two above methods, UI objects will be automatically generated. The generated UI objects can be customized through the use of DataTemplates.
    5. Example controls are the ListBox, ListView, DataGrid, TabControl, ComboBox, Menu and ItemsControl.
  5. See for the further details...

Friday, November 18, 2011

Exceptions and Validation

Validation is only a concern for TwoWay data bindings. When Silverlight moves data from your view back into your model – how do you control the values your model accepts? And how do you inform the user when they’ve entered illegal input?

First, let’s talk about the problems that can occur when data flows back into your model. The first potential problem is that Silverlight may not be able to convert the user’s input into the data type the model requires. This can happen when the user types “abc” into a field that expects integers, or types “123” into a field that requires a date. Some of these problems you try to avoid by using restricted controls (a calendar control for the user to enter a date, as an example), but this won’t avoid all conversion problems.

Another type of problem happens when Silverlight can convert the user’s input into the proper type, but your business logic determines the value of the data is illegal. One example is trying to place an order for –1 books. You want the quantity value of an order to always be positive. In these cases you must your model throw an exception when Silverlight sets the value. How do you know the exception occurred?

Silverlight can tell you about both types of validation errors, but you must set two properties on a binding to true. The first property is the ValidatesOnExceptions property. This property tells Silverlight to catch exceptions that occur when data moves from the view to the model. Again – this will be the exceptions thrown when trying to convert the user’s input, AND any exceptions thrown by the model itself.

In order to know about these exceptions you must also set the NotifyOnValidationError property to true. When true, Silverlight will raise a BindingValidationError event. This event will bubble up the visual tree of elements, so you can subscribe to the event on the element that is data bound, or at the element’s parent level, or the parent’s parent, and so on. In the following XAML we subscribe at the UserControl level.

<UserControl Width="400"      x:Class="DataBindingDemo.EditTimeCard"     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"      xmlns:local="clr-namespace:DataBindingDemo"      BindingValidationError="UserControl_BindingValidationError" >     <UserControl.Resources>         <local:DateFormatter x:Key="dateFormatter" />     UserControl.Resources>     <Grid x:Name="LayoutRoot" Background="White">         <StackPanel>             <TextBlock Text="Total Hours"/>             <TextBox Margin="10" Text="{Binding                                          ValidatesOnExceptions=true,                                         NotifyOnValidationError=true,                                         Mode=TwoWay,                                         Path=TotalHours}"/>             <TextBlock Text="Start Date"/>              <TextBox Margin="10" Text="{Binding                                         Mode=TwoWay,                                         Converter={StaticResource dateFormatter},                                         ConverterParameter='{0:d}',                                         Path=PayPeriod.Start}"/>             <TextBlock Text="End Date"/>             <TextBox Margin="10" Text="{Binding Path=PayPeriod.End}"/>                     StackPanel>     Grid> UserControl> 

The BindingValidationError event can tell you the source of an error, and also if the error is being added (the user just entered bad input) or removed (the user corrected a bad input). We can use this information to change elements on the screen, such as making the control that is the source of the failure turn red.

private void UserControl_BindingValidationError(     object sender, ValidationErrorEventArgs e) {     var control = e.OriginalSource as Control;     switch (e.Action)     {         case ValidationErrorEventAction.Added:             control.Background = new SolidColorBrush(_red);             break;         case ValidationErrorEventAction.Removed:             control.Background = new SolidColorBrush(_white);             break;     } } 

The DataGrid

Grids play a prominent role in many applications, and Silverlight includes a DataGrid control in the System.Windows.Controls.Data assembly. You can drag this control from the Visual Studio Toolbox window into your XAML file and Visual Studio will take care of referencing the correct assemblies and adding the proper XML namespace definitions to your XAML file. The DataGrid supports editing, sorting, and drag n’ drop columns. The DataGrid, like the ListBox, has an ItemsSource property we can use to set a binding expression. Simply setting up the binding after placing the grid in your XAML is enough to get started, as the grid is capable of auto-generating columns from the model (the grid will create a column for every public property).

<data:DataGrid AutoGenerateColumns="True"                 HeadersVisibility="All"                ItemsSource="{Binding}"                                       RowBackground="Cornsilk"                 AlternatingRowBackground="BlanchedAlmond"                ColumnWidth="85" RowHeight="30"                IsReadOnly="True" CanUserResizeColumns="False">         data:DataGrid>

Simple customizations of the grid are possible just by setting some properties - background colors, grid lines, and resizable columns. For more control you can define the exact columns you want the grid to use by setting the Columns property. The Silverlight grid includes three types of columns: a GridTextColumn (to display text), a DataGridCheckBoxColumn (great for boolean properties), and a DataGridTemplate column. Like most templates in Silverlight, you can use a DataGridTemplate column to display nearly anything you want inside a grid – use calendars, stack panels, colored rectangles, etc. Notice the TimeCards column in the above screen shot. That grid is using auto-generated columns and doesn’t know how to display a property that is a collection. Now look at the following XAML:

<Grid x:Name="LayoutRoot" Background="White">     <data:DataGrid AutoGenerateColumns="False"                            ItemsSource="{Binding}"                                   IsReadOnly="False">         <data:DataGrid.Columns>             <data:DataGridTextColumn Binding="{Binding Name}" Width="50" />             <data:DataGridTemplateColumn>                 <data:DataGridTemplateColumn.CellTemplate>                     <DataTemplate>                         <data:DataGrid AutoGenerateColumns="True"                                         ItemsSource="{Binding TimeCards}"/>                      DataTemplate>                 data:DataGridTemplateColumn.CellTemplate>             data:DataGridTemplateColumn>         data:DataGrid.Columns>     data:DataGrid> Grid> 

In the above XAML we’ll turn off auto-generated columns and explicitly define the columns for display. Using the DataGridTemplateColumn we can even define a nested data grid to display all the time cards for an employee. For more information about the grid control, I highly recommend the following blog posts.

Also, be aware of a “bug” in the Silverlight 2.0 version of the DataGrid. Jesse Liberty describes the problem in his post “It Ain’t You, Babe … A Not-a-bug Bug in DataGrid”. The problem is that validation errors are tricky to catch with the DataGrid. Let’s look at validation next.

Data Binding Modes

Silverlight features three data binding modes. The first mode, the default mode, is one-way data binding. In one-way data binding data moves from the model to the view only. Changes made in the view, such as inside of a TextBox control, will not change the underlying property in the model.

Two-way data binding allows changes to propagate back to the model. Two-way data binding is perfect for editable forms, but you do need to explicitly set the two-way mode. An example is shown below.

<TextBox Margin="10" Text="{Binding                              Mode=TwoWay,                             Path=TotalHours}"/> <TextBlock Text="Start Date"/>  <TextBox Margin="10" Text="{Binding                             Mode=TwoWay,                             Converter={StaticResource dateFormatter},                             ConverterParameter='{0:d}',                             Path=PayPeriod.Start}"/> 

The mode is the OneTime mode. When you use OneTime binding, Silverlight will move data from the model to the view element only once. Even if the model uses INotifyPropertyChanged and the underlying data changes, the changes will not be reflected in the UI.

Beyond Simple Text

Binding works with all types of objects – not just simple primitive types like integers and strings. In the XAML below we are going to databind a property named Brush to the Fill property of a Rectangle.

<ListBox ItemsSource="{Binding}">     <ListBox.ItemTemplate>         <DataTemplate>             <StackPanel Orientation="Horizontal">                 <TextBlock Text="{Binding Code}" Width="90" />                 <Rectangle Fill="{Binding Brush}"                            Width="100" Height="12"                            VerticalAlignment="Center" />             StackPanel>         DataTemplate>     ListBox.ItemTemplate> ListBox> 

This XAML can bind to a collection of BrushDisplay objects we create in code. Each BrushDisplay has a Code property (of type string) that represents the hexadecimal RGB values for a color, and a SolidColorBrush property named Brush to paint the actual color. The screen shot on the right is an excerpt of what the code below will create.

byte[] v = { 0x00, 0x33, 0x66, 0x99, 0xCC, 0xFF };pretty colors in silverlight   var list = new List<BrushDisplay>(); for (int r = 0; r < v.Length; r++)   for(int g = 0; g < v.Length; g++)     for(int b =0; b < v.Length; b++)       list.Add(         new BrushDisplay()         {           Code = "0x" + (v[r] + (v[g] << 8) + (v[b] << 16))                          .ToString("X"),           Brush = new SolidColorBrush(               Color.FromArgb(255, v[r], v[g], v[b]))         });              this.DataContext = list; 

Of course not every data source may map perfectly to its destination. We might need to massage some data as it travels into the view, and vice versa (more on two-way data binding in a bit). In these scenarios we need a value converter. A value converter implements the IValueConverter interface. Values converters are powerful because they allow you to inject some logic into the binding process to perform conversions and formatting (a popular use of value converters is to format numbers and dates).

If you are displaying a DateTime, for example, the default conversion during databinding will create the display seen on the right. ugly DateTimeIf we only want to display the date (and no time), we can use a value converter. Value converters are easy to create – you only need to implement Convert and ConvertBack methods. The class below is designed to convert dates to strings and back again.

public class DateFormatter : IValueConverter {     public object Convert(object value, Type targetType,                            object parameter, CultureInfo culture)     {         if (parameter != null)         {             string formatString = parameter.ToString();              if (!string.IsNullOrEmpty(formatString))             {                 return string.Format(culture, formatString, value);             }         }          return value.ToString();     }      public object ConvertBack(object value, Type targetType,                                object parameter, CultureInfo culture)     {         if (value != null)         {             return DateTime.Parse(value.ToString());         }         return value;     } } 

To use this new formatter we need to include it in our XAML. You can add formatters as resources inside of user controls, pages, and even at the application level. In the XAML below we are adding an instance of the formatter inside a user control’s resource dictionary with a key of “dateFormatter”. Notice we also include an XML namespace to CLR namespace mapping (xmlns:local="clr-namespace:DataBindingDemo") so that the XAML parser knows where to find the formatter.

<UserControl Width="400"      x:Class="DataBindingDemo.EditTimeCard"     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"      xmlns:local="clr-namespace:DataBindingDemo" >     <UserControl.Resources>         <local:DateFormatter x:Key="dateFormatter" />     UserControl.Resources>

We can then use the formatter in a data binding expression. The following XAML points to the dateFormatter key, so the formatter will be found in the application’s resources. Notice we can also pass along a ConverterParamter. In this case a “{0:d}” will tell the String.Format call to format the DateTime into a short date format (such as 1/1/2008 for a United States English culture setting).

<TextBox Margin="10" Text="{Binding                               Converter={StaticResource dateFormatter},                             ConverterParameter='{0:d}',                             Path=PayPeriod.Start}"/> 

Thursday, November 17, 2011

Detecting Changes

Silverlight has the capability to update the UI when the underlying model changes. For example, if we are displaying the total number of hours worked by an employee, and we change an employee’s TotalHours property, the UI will automatically update to reflect the new total. For this to work we need our model objects to implement a magic interface.

For collections this magic interface is the INotifyCollectionChanged interface.

Fortunately, there is already a collection class we can use that implements INotifyCollectionChanged – this is ObservableCollection. When you add or remove objects to an observable collection, the observable collection will automatically raise a CollectionChanged event. When Silverlight establishes a data binding it will look to see if the model collection implements the INotifyCollectionChanged interface and if so will automatically subscribe to the event. This means you don’t have any additional work to do when binding to an observable collection. If we bind an observable collection to the ItemsSource property of a ListBox, for example, then the ListBox will automatically display new objects we add to the collection, and will automatically remove objects we delete from the collection.

For non-collections the magic interface is the INotifyPropertyChanged interface. This interface demands that an object implement a PropertyChanged event. A typical implementation is shown below.

public class Employee : INotifyPropertyChanged {     string _name;     public string Name     {         get { return _name; }         set          {             if (_name != value)             {                 _name = value;                 RaisePropertyChanged("Name");             }         }     }      int _departmentID;     public int DepartmentID     {         get { return _departmentID; }         set         {             if (_departmentID != value)             {                 _departmentID = value;                 RaisePropertyChanged("DepartmentID");             }         }     }      public event PropertyChangedEventHandler PropertyChanged;      void RaisePropertyChanged(string propertyName)     {         var handler = PropertyChanged;         if (handler != null)         {             handler(this, new PropertyChangedEventArgs(propertyName));         }     }                } 

All we need to do is raise the PropertyChanged event while passing along the name of the property that changed as an event argument. Silverlight will automatically subscribe to this event when it binds to an object that implements INotifyPropertyChanged. When we make changes to the underlying object the changes will be reflected immediately in the UI.

Binding To Collections

Most data binding scenarios involve lists – such as a list of employees or a list of products. For these scenarios its common to use the Silverlight ListBox control. The ListBox knows how to display a collection of items by replicating a data template for each item. A data template describes the controls you want to use when displaying each individual item in a collection. You can almost think of a data template as a mini-control because it contains a bunch of child controls. The ListBox simply creates one instance of this mini-control for each object in the model’s collection. An example is shown below.

<ListBox ItemsSource="{Binding}">     <ListBox.ItemTemplate>         <DataTemplate>             <TextBlock Text="{Binding Name}">TextBlock>         DataTemplate>     ListBox.ItemTemplate>                         ListBox> 

The ItemsSource property of the ListBox is the property that will reference the collection we want to databind. In this case we use the binding expression {Binding}, meaning we want the “whole” of the DataContext. In this scenario the model itself is a collection of objects. You could also drill into the model by with an expression such as {Binding Department.Employees}.

Notice the ItemTemplate of the list is set to a DataTemplate. Inside the DataTemplate is a single TextBlock to display the Name property of each object in the model. In this case we are using just a single TextBlock, but the powerful DataTemplate could include multiple controls, such as text blocks, images, videos, and colorful graphical elements. When the above XAML is combined with the code shown below, the result will be the image shown on the right.

var employees = new List<Employee>()image  {     new Employee { Name = "Scott" },     new Employee { Name = "Poonam"},     new Employee { Name = "Paul" } }; this.DataContext = employees; 

Quite often you’ll find data templates inside the resource section of a Page or application. The beauty of resources in Silverlight is that you can reuse resources across multiple pages in an application, and you also keep your XAML a little cleaner. Using such an approach with the above XAML would look like the following.

<UserControl.Resources>     <DataTemplate x:Key="employeeTemplate">         <TextBlock Text="{Binding Name}">TextBlock>     DataTemplate>       UserControl.Resources>      <ListBox ItemsSource="{Binding}"           ItemTemplate="{StaticResource employeeTemplate}"> ListBox> 

We can now reference the data template for displaying an employee by using the {StaticResource} binding and specifying a key of employeeTemplate. Although this template resource is only available inside of the same user control, we could take the template and place it in the resources section of the App.xaml file and reuse the template throughout the application.

Wednesday, November 16, 2011

Simple Data Binding

Databinding is the magic that that sits between your objects (know as a model) and the UI (known as a view). The model isn’t concerned with how the data will appear in front of the user – it’s job is to hold the data. The view, meanwhile, can take the model and render it inside of grids, charts, and lists.



There are only two concepts you need to know for basic data binding. First is the concept of a binding expression. A binding expression is used inside the XAML of a Silverlight component to describe the name of the property that you want fetched from the model. A binding expression lives inside of curly braces ({ and }), and you can see three examples in the source code below.

###########################################################################################
<UserControl x:Class="DataBindingDemo.SimpleBinding"     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">     <StackPanel>         <TextBlock Text="{Binding Name}" />         <TextBlock Text="{Binding Path=ID}" />         <TextBlock Text="{Binding Department.Name}"/>     StackPanel> UserControl>

###########################################################################################
The first TextBlock in the XAML is using a binding expression on its Text property. The binding expression is telling Silverlight to pull the value for this Text property from the Name property of the model. The second TextBlock is fetching the ID property of the model using a slightly different (but equivalent) binding expression (the Path word is optional in simple expressions). You can even navigate an object hierarchy as demonstrated in the third TextBlock. In this case Silverlight will find a Department property on the model, then fetch the Name property from that object and use that for the Text property. All of the data binding options (such as the "Path”) are expressed as attributes inside the expression. We’ll see more options later in the article.



How does Silverlight know where the model comes from? That’s the second concept in data binding – the data context.




Most Silverlight controls will expose a DataContext property. By setting this property you are effectively telling Silverlight “here is the model to use”. Thus, the following C# code, combined with the above XAML, will produce the display shown to the right.



Employee employee = new Employee()
{
Name = "Scott",
ID = 1,
Department = new Department() { Name = "Engineering" }
};
this.DataContext = employee;


You can set the DataContext at anytime as long as the underlying Silverlight component is initialized. In the above code, “this” represents the user control, so we are setting the data context for the entire control, and all the TextBlocks inside will fetch values from the same model object. This is because Silverlight travels “up” the tree of controls to find the DataContext where a model exists.



For example, the {Binding Name} in the first TextBlock will first look at the DataContext on the TextBlock itself. When that fails to find a model there it will look at the DataContext of the StackPanel that is a parent of the TextBlock. When that fails, Silverlight will find the DataContext at the UserControl level. This “context inheritance” means we only need to set the DataContext once for the entire page and it flows downwards, but if need be we could also set multiple DataContext properties inside the tree of controls, and even override inherited contexts.

WPF and Silverlight Layout Controls

Windows Presentation Foundation has dynamic layout (also known as automatic layout)
panel themselves are responsible for sizing ans positioning elements based on different layout models.

Type of Layout :(every layout derived from Panel Class)


DockPanel
Grid
StackPanel
UniformGrid
WrapPanel
Panel defines a property names Children used to store the child elements. Children object can be UICollection. Like image,shape,textblock and control objects.

1.StackPanel

Its used to arrange the controls vertically or horizontal stack.

XAML



< /TextBlock>


C#

StackPanel s=new StackPanel();
Button b=new Button();
b.Content=”Click”;
TextBlock t=new TextBlock();
t.Content=”run”;
s.Children.Add(b);
s.Children.Add(t);

Orientation Property

We can specify the children orientation using Orientation property of StackPanel. s.Orientation=Orientation.Horizontal;

Vertical and Horizontal Alignment

s.HorizontalAlignment=HorizontalAlignment.Horizontal (or) s.VerticalAlignment=VerticalAlignment.Vertical


2.WrapPanel


WrapPanel is similar to the StackPanel but in the WrapPanel Child elements can wrap to the next column or row automatically if there is not enough room. WrapPanel is used to add unknown number of controls like Non-Detail view in WindowsExplorer. And also we can set ItemHeight and ItemWidth properties that we can use to enforce uniform height or width, Orientation Property is same as StackPanel.


WrapPanel s=new WrapPanel();
s.ItemHeight=100;
s.ItemWidth=100;
s.Orientation=Orientation.Vertical;
Button b=new Button();
b.Content=”Click”;
TextBlock t=new TextBlock();
t.Content=”run”;
s.Children.Add(b);
s.Children.Add(t);

3.DockPanel

use of the dockpanel is automates the positioning of elements against the inside edges of their parents. We can create dockpanel in C# Like Follows.

DockPanel d=new DockPanel();

And we can set dockpanel object into the window content property.
Windowobject.Content=d;

now window layout begin with dockpanel and then we can add other type panel or control like that . Adding children in dock panel is same syntax as with other panels.

Dock.Children.Add(ctl)

But with that we need to specify on which side of the DockPanel you want control docked.
Example if you want dock the control on right side of panel you need to specify like this .

DockPanel.SetDock(ctrl,Dock.Right);
SetDock is a static method of DockPanel Class. Argument should be control and dock style.

Dock Enumeration


Dock.Left
Dock.Right
Dock.Bottom
Dock.Top
Note :
SetDock Method call may come before or after adding the control into the panel.

Another Method for setting Dock for the control

Using attached property concept like follows.
Controlobject.SetValue(DockPanel.DockProperty,Dock.Right);

The last control is not docked at all but occupies the leftover interior space. This behavior is by default true setting of the DockPanel property LastChildFill. If we set LastChildFill=false means the last control also docked. And leftover space is unfilled .

4.Grid

its used to hosts the children in a grid of rows and columns. It has property named ShowGridLines. Its used to display the grid lines. GridLenth() is used to specify the Grid Height and Width. Constructor will take two arguments – one is value and another one is GridUnitType.

Example

GridLenth glen=new GridLength(100,GridUnitType.Pixel);
Type Of GriUnit :
GridUnitType.Auto
GridUnitType.Star
GridUnitType.Pixel

Example

Grid g=new Grid();
RowDefinition rdef=new RowDefinition();
rdef.Height=GridLength.Auto;
g.RowDefinitions.Add(rdef);
RowDefinition rdef1=new RowDefinition();
rdef1.Height=GridLength.Auto;
g.RowDefinitions.Add(rdef1);
ColumnDefinition cdef=new ColumnDefinition();
cdef.Width=GridLength.Auto;
g.ColumnDefinitions.Add(cdef);
ColumnDefinition cdef1=new ColumnDefinition();
cdef1.Width=GridLength.Auto;
g.ColumnDefinitions.Add(cdef1);
Adding Control into the Grid.
g.Children.Add(ctrl);
Grid.SetRow(ctrl,rowno);
Grid.SetColumn(ctrl,colno);
Adding RowSpan and ColumnSpan
Grid.SetRowSpan(ctrl,noofrow);
Grid.ColumnSpan(ctrl,noofcol);

5.UniformGrid

its similar to the Grid . Except that all the rows and columns are equal Height and Width.