Sunday, August 07, 2011

Load Treeview control with checkbox and Bind with entity object using Silverlight 4.0


Load Treeview control with checkbox and Bind with entity object using Silverlight 4.0
Populate tree view control with others controls like check box, Image etc. below I am giving one example to populate tree view control by binding with entity object, following code will demonstrate below functionality
  • How to add check box control and image control into the tree view.
  • How to populate tree view control using entity objects
  • How to do check un-check all check boxes when clicks on parent check box.

This code has been tested and developed using Silverlight 4.0 and Visual Studio 2010.
I spend lots of time to learn to understand hierarchical structure in XMAL file and C# code to do check un-check all while clicking of parent node check box and all child node should automatically get selected.

Common mistake I did while writing XMAL code
  1. Correct Item Source Binding, here object should eject same as you declared like: If you have declared State object as CountryState then binding object name must be “CountryState” NOT “States”       public  List<States> CountryState { get; set; }
  1. Use correct check box event, like this case you should use check box “Click” event NOT “Checked” event  Use: Click="chkArea_Click" with check box NOT Checked="chkArea_Checked"
Example
Below I have taken example of Countries to display hierarchical data structure, one country has multiple States, each State has multiple Cities and Each City has multiple Area.
Namespace
using System.Windows.Controls;

Source Code
Global variables
string CheckBoxImage = @"/TreeViewControl;component/Images/RedCircle.png";

Make one folder name “Images” into project root and add one red circle image into it.
Example: @”/;component/Images
List countries = new List();

Entity Classes
 public class Country
 {
   //Default Constructor
   public Country() { CountryState = new List<States>(); }
   public string Name { get; set; }
   public int Id { get; set; }
   public bool IsSelected { get; set; }
   public string CountryImg { get; set; }
   public  List<States> CountryState { get; set; }
 } 
    public class States
    {
        public States() { StateCities = new List<City>(); }
        public string Name { get; set; }
        public int Id { get; set; }
        public bool IsSelected { get; set; }
        public string StateImg { get; set; }
        public List<City> StateCities { get; set; }
    } 
    public class City
    {
        public City() { CitieAreas = new List<Area>(); }
        public string Name { get; set; }
        public int Id { get; set; }
        public bool IsSelected { get; set; }
        public string CityImg { get; set; }
        public List<Area> CitieAreas { get; set; }
    } 
    public class Area
    {
        public string Name { get; set; }
        public int Id { get; set; }
        public bool IsSelected { get; set; }
        public string AreaImg { get; set; }
    }  

Code to Load entity object
private void LoadTreeview()
{
   Country ctn; States sts; City cty; Area area;int con;

   for (con = 0; con <= 1; con++)
   {
     ctn = new Country();
     ctn.Id = con;
     ctn.Name = "Country-" + con;
     ctn.CountryImg = CheckBoxImage;

   for (int s = 0; s < 1; s++)
   {
     sts = new States();
     sts.Id = con + s;
     sts.Name = "State-" + con ;
     sts.StateImg = CheckBoxImage;
     ctn.CountryState.Add(sts);

   for (int c = 0; c <= ctn.CountryState.Count - 1; c++)
   {
    cty = new City();
    cty.Id = con + c;
    cty.Name = "City-" + con;
    cty.CityImg = CheckBoxImage;
    ctn.CountryState[c].StateCities.Add(cty);

    for (int a = 0; a <= ctn.CountryState[c].StateCities.Count - 1; a++)
    {
      area = new Area();
      area.Id = con + a;
      area.Name = "Area-" + con
      area.AreaImg = CheckBoxImage;
      ctn.CountryState[c].StateCities[a].CitieAreas.Add(area);
    }
    }
    } 
       countries.Add(ctn);
    } 
    //Bind Object with ThreeView Control
    this.treeView.ItemsSource = null;
    this.treeView.ItemsSource = countries;          
    }

Check Box click (Country Check box clicked) code

Note: DO NOT WRITE THIS CODE IN CHECK BOX CHECKED EVENT (“chkCountry_Checked”), if you do so this event will fire recursively and system will throw an exception “Error HRESULT E_FAIL has been returned from a call to a COM component.”, when try to bind object.
Loop through the object and set IsSelected property true on Country check box click ..

private void chkCountry_Click(object sender, RoutedEventArgs e)
{ 
  CheckBox checkBox = sender as CheckBox;
  bool? selected = checkBox.IsChecked;

  int id = Convert.ToInt32(checkBox.Tag);

  if (selected.Value)
  {
    foreach (Country con in countries)
    {
      if (con.Id == id)
      {
        con.IsSelected = true;
        foreach (States s in con.CountryState)
        {
           s.IsSelected = true;
           foreach (City c in s.StateCities)
           {
             c.IsSelected = true;
foreach (Area a in c.CitieAreas)
              {
                a.IsSelected = true;
              }
            }
        }
      }
    }
  }
  else if (selected.HasValue && selected.Value == false
  {
     foreach (Country con in countries)
     {
        if (con.Id == id)
        {
          con.IsSelected = false;
          foreach (States s in con.CountryState)
           {
              s.IsSelected = false;
              foreach (City c in s.StateCities)
               {
                 c.IsSelected = false;
                  foreach (Area a in c.CitieAreas)
                  {
                     a.IsSelected = false;
                  }
                           }
              }
             }
           }
         }

 //Bind Object with ThreeView Control with modified value
 this.treeView.ItemsSource = null;
 this.treeView.ItemsSource = countries;
}

Note: you can rewrite above code avoiding loop inside loop see the article to avoid loops

XMAL Code
You can directly write below code inside User Control Tag in XAML file, all below highlighted color display, links between parent s nodes to child, basically you need to create parents-child relationship here.
<Grid x:Name="LayoutRoot" Background="White">

<StackPanel x:Name="stackMain">
<StackPanel.Resources>

<sdk:HierarchicalDataTemplate x:Key="AreaKey">
<StackPanel Orientation="Horizontal">
<Image x:Name="AreaImg" Source="{Binding AreaImg}" Margin="0,0,5,0" />
<CheckBox Tag="{Binding Id}" x:Name="chkArea"  IsChecked= "{Binding IsSelected }" Margin="0,0,5,0" Click="chkArea_Click" />
<ContentControl Name="AreaName" Content="{Binding Name}" Margin="5,0,0,0" />
StackPanel>
sdk:HierarchicalDataTemplate>

<sdk:HierarchicalDataTemplate x:Key="CitiKey" ItemsSource="{Binding CitieAreas}" ItemTemplate="{StaticResource AreaKey}">
<StackPanel Orientation="Horizontal">
<Image x:Name="CityImg" Source="{Binding CityImg}" Margin="0,0,5,0" />
<CheckBox Tag="{Binding Id}" x:Name="chkCity"  IsChecked= "{Binding IsSelected }" Margin="0,0,5,0" Click="chkCity_Click" />
<ContentControl Name="CityName" Content="{Binding Name}" Margin="5,0,0,0" />
StackPanel>
sdk:HierarchicalDataTemplate>

<sdk:HierarchicalDataTemplate x:Key="StateKey" ItemsSource="{Binding StateCities}" ItemTemplate="{StaticResource CitiKey}">
<StackPanel Orientation="Horizontal">
<Image x:Name="StateImg" Source="{Binding StateImg}" Margin="0,0,5,0" />
<CheckBox Tag="{Binding Id}" x:Name="chkState"  IsChecked= "{Binding IsSelected }" Margin="0,0,5,0" Click="chkState_Click" />
<ContentControl Name="CountryName" Content="{Binding Name}" Margin="5,0,0,0" />
StackPanel>
sdk:HierarchicalDataTemplate>

<sdk:HierarchicalDataTemplate x:Key="CountryKey" ItemsSource="{Binding CountryState}" ItemTemplate="{StaticResource StateKey}">
<StackPanel Orientation="Horizontal">
<Image x:Name="CountryImg" Source="{Binding CountryImg}" Margin="0,0,5,0" />
<CheckBox Tag="{Binding Id}" x:Name="chkCountry"  IsChecked= "{Binding IsSelected }" Margin="0,0,5,0" Click="chkCountry_Click" />
<ContentControl Name="CountryName" Content="{Binding Name}" Margin="5,0,0,0" />
StackPanel>
sdk:HierarchicalDataTemplate>
  
StackPanel.Resources>
<sdk:TreeView x:Name="treeView" ItemTemplate="{StaticResource CountryKey}"  HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" Margin="0" Background="{x:Null}" >

<sdk:TreeView.ItemContainerStyle>
<Style TargetType="sdk:TreeViewItem">
<Setter Property="IsExpanded" Value="True" />
Style>
sdk:TreeView.ItemContainerStyle>

sdk:TreeView>
StackPanel>

Grid>

No comments: