Sunday, February 27, 2011

DataGrid, Create and load datatemplate on the fly.

Recently , I was investigating how to port a winform application to use WPF.  the winform application is intensively using DataGrid. But it is using a lot of code to handle the style and appearance. 

In WPF, we have data binding which is very flexible. Here is what I learned recently.

1.How to bind columns on the fly using code behind.

Assume you have a model class, which can return you a DataTable object, while the columns in the DataTable varies by the input parameter which you passed in when you invoke the function.  The data in the table cell is a custom data type(SiteData),base on the DataType property of MyCellData object, we should use different style to differentiate it,Base on the column name we should decide hide or show the column,How to bind the DataTable to a DataGrid?

To be clear, I post a function to generated the data here, so based on the code, you know What I mean.

   1:   public DataTable ToDataTable()
   2:          {
   3:              DataTable dt = new DataTable();
   4:              this.CreateDummyData();
   5:              dt.Columns.Add("Row1", typeof(RowHeadInfo));
   6:              dt.Columns.Add("Row2", typeof(RowHeadInfo));
   7:              for (var i = 2000; i <= 2020; i++)
   8:              {
   9:                  for (var j = 0; j <= 4; j++)
  10:                  {
  11:                      if(j == 0)
  12:                          dt.Columns.Add(string.Format("Y{0}", i, j), typeof(SiteData));
  13:                      else
  14:                          dt.Columns.Add(string.Format("Y{0}Q{1}", i, j), typeof(SiteData));
  15:                  }
  16:              }
  17:              foreach (var item in this._listRows)
  18:              {
  19:                  item.ToDataTable(dt);
  20:              }
  21:              return dt;
  22:          }



You might say just set the itemssource to the datatable, yeah, we should do that anyway, but it is not that easy, cause the data in the table is a custom data type, so you have to specify a binding to tell the grid which property to display, and we need trigger to change the style of display.


Eventually, we can’t write the DataGridColumns definition in xaml file. there are two solutions.


a)You can use a loop to go through the columns in the DataTable and then use code to add column to the DataGrid.  use this method, you have to set the AutoGeneratedColumns to false.


b)You can set the AutoGenerateColumn to true, while write a function to handle the AutoGeneratingColumn event. in this function , you can create and load data template use code.


   1:  private void dataGrid1_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
   2:          {
   3:              if (e.PropertyType == typeof(RowHeadInfo))
   4:              {
   5:                  DataGridTextColumn dgtc = new DataGridTextColumn();
   6:                  dgtc.IsReadOnly = true;
   7:                  dgtc.Binding = new Binding(e.PropertyName + ".RowName");
   8:                  dgtc.CellStyle = this.FindResource("RowHeaderSelectedStyle") as Style;
   9:                  dgtc.HeaderStyle = this.FindResource("NormalHeaderStyle") as Style;
  10:                  e.Column = dgtc;
  11:              }
  12:              else if (e.PropertyType == typeof(SiteData))
  13:              {
  14:                  DataGridTextColumn dgtc = new DataGridTextColumn();
  15:                  dgtc.Width = 50;
  16:                  dgtc.Binding = new Binding(e.PropertyName)
  17:                  {
  18:                      
  19:                      Converter = new DataCellConverter(),
  20:                      Mode = BindingMode.TwoWay
  21:                  };
  22:                  
  23:                  if (e.PropertyName.Contains("Q"))
  24:                  {
  25:                      dgtc.Visibility = Visibility.Hidden;
  26:                      dgtc.HeaderStyle = this.FindResource("NormalHeaderStyle") as Style;
  27:                  }
  28:                  else
  29:                  {
  30:                      dgtc.HeaderStyle = this.FindResource("NormalHeaderStyleWithCheckBox") as Style;
  31:                  }
  32:                  
  33:                  dgtc.CanUserSort = false;
  34:                  dgtc.Header = e.PropertyName;
  35:                  
  36:                  string strStyle = Properties.Resources.NormalDataCellStyle;
  37:                  string strValue = strStyle.Replace("{0}", e.PropertyName);
  38:                  XmlReader xr = XmlReader.Create(new StringReader(strValue));
  39:                  Style st = (Style)XamlReader.Load(xr);
  40:                  dgtc.CellStyle = st;
  41:                  e.Column = dgtc;
  42:              }
  43:          }





   1:  <Style  TargetType="{x:Type DataGridCell}"  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
   2:              <Setter Property="Background" Value="Green" />
   3:              <Setter Property="Foreground" Value="White" />
   4:              <Setter Property="HorizontalAlignment" Value="Stretch" />
   5:              <Setter Property="VerticalAlignment" Value="Center" />
   6:              <Style.Triggers>
   7:                  <DataTrigger Binding="{Binding Path={0}.SiteDataType}">
   8:                      <DataTrigger.Value>
   9:                          REPORT
  10:                      </DataTrigger.Value>
  11:                      <Setter Property="Background" Value="Red" />
  12:                  </DataTrigger>
  13:                  <DataTrigger Binding="{Binding Path={0}.SiteDataType}">
  14:                      <DataTrigger.Value>
  15:                          ESTIMATE
  16:                      </DataTrigger.Value>
  17:                      <Setter Property="Background" Value="Yellow" />
  18:                  </DataTrigger>
  19:                  <Trigger Property="IsSelected" Value="True">
  20:                      <Setter Property="Background" Value="Green" />
  21:                  </Trigger>
  22:              </Style.Triggers>
  23:          </Style>

No comments:

Post a Comment