2009年11月27日 星期五

WPF DataGrid

1. Create a WPF Application through Visual Studio 2008 SP1 and Dot Net Framework 3.5 SP1.

In Windows1.xaml

< Window x:Class="WpfDataGrid.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dg="http://schemas.microsoft.com/wpf/2008/toolkit"
Title="Window1" Height="300" Width="600">




< dg:DataGridTextColumn Header="First Name" Binding="{Binding Path=FirstName}"/>
< dg:DataGridTextColumn Header="Last Name" Binding="{Binding Path=LastName}"/>
< dg:DataGridTextColumn Header="Address" Binding="{Binding Path=Address}"/>
< dg:DataGridCheckBoxColumn Header="New?" Binding="{Binding Path=IsNew}"/>
< dg:DataGridCheckBoxColumn Header="Subscribed?" Binding="{Binding Path=IsSubscribed}"/>







In Windows1.xaml.cs
First, define a class to generate data to display.

public class Customer
{
public String FirstName { get; set; }
public String LastName { get; set; }
public String Address { get; set; }
public Boolean IsNew { get; set; }

// A null value for IsSubscribed can indicate
// "no preference" or "no response".
public Boolean? IsSubscribed { get; set; }

public Customer(String firstName, String lastName,
String address, Boolean isNew, Boolean? isSubscribed)
{
this.FirstName = firstName;
this.LastName = lastName;
this.Address = address;
this.IsNew = isNew;
this.IsSubscribed = isSubscribed;
}

public static ObservableCollection GetSampleCustomerList()
{
return new ObservableCollection (new Customer[4] {
new Customer("A.", "Zero",
"12 North Third Street, Apartment 45",
false, true),
new Customer("B.", "One",
"34 West Fifth Street, Apartment 67",
false, false),
new Customer("C.", "Two",
"56 East Seventh Street, Apartment 89",
true, null),
new Customer("D.", "Three",
"78 South Ninth Street, Apartment 10",
true, true)
});
}
}


By this way, we could see the simple WPF DataGrid.


Run this program, one problem occured. If you would like to change the status of the checkbox, you have to click twice. First click will focus on the row, and second click will change the state of the checkbox.
The solution is to use DataGridTemplateColumn to replace the DataGridCheckBoxColumn.

















At this moment, everything seems to be ok. But in practice, if we could not make sure how many columns we have, what should we do?
So we need to create DataGrid programmatically.

In Windows1.xaml, we don't need the defination of the columns, just leave the declaration of < dg:DataGrid/>.

< Window x:Class="WpfDataGrid.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dg="http://schemas.microsoft.com/wpf/2008/toolkit"
Title="Window1" Height="300" Width="600">


< dg:DataGrid AutoGenerateColumns="False" Margin="22,24,20,26" Name="dataGrid"/>





In Windows.xaml.cs, I wrote a method InitDataGrid and put it after InitializeComponent().

private void InitDataGrid()
{
dataGrid.ItemsSource = Customer.GetSampleCustomerList();

dataGrid.Columns.Clear();

dataGrid.Columns.Add(GetTextColumn("First Name", "FirstName"));
dataGrid.Columns.Add(GetTextColumn("Last Name", "LastName"));
dataGrid.Columns.Add(GetTextColumn("Address", "Address"));
dataGrid.Columns.Add(GetCheckBoxColumn("New?", "IsNew"));
dataGrid.Columns.Add(GetCheckBoxColumn("Subscribed?", "IsSubscribed"));
}


private DataGridTextColumn GetTextColumn(string _header, string _binding)
{
DataGridTextColumn col = new DataGridTextColumn();
col.Header = _header;
if (_binding != null && _binding != "")
col.Binding = GetBinding(_binding, BindingMode.OneWay);
return col;
}


private DataGridTemplateColumn GetCheckBoxColumn(string _header, string _binding)
{
DataGridTemplateColumn col = new DataGridTemplateColumn();
col.Header = _header;

Dictionary values = new Dictionary();
//values.Add(CheckBox.StyleProperty, FindResource("DataGridCheckBoxStyle"));

Dictionary bindings = new Dictionary();
bindings.Add(CheckBox.IsCheckedProperty, GetBinding(_binding, BindingMode.TwoWay));

col.CellTemplate = GetDataTemplate(typeof(CheckBox), values, bindings);
return col;
}


private DataTemplate GetDataTemplate(Type _t, Dictionary _values,
Dictionary _bindings)
{
DataTemplate dt = new DataTemplate();
FrameworkElementFactory factory = new FrameworkElementFactory(_t);
dt.VisualTree = factory;
//SetValue
foreach (KeyValuePair kvp in _values)
{
factory.SetValue(kvp.Key, kvp.Value);
}
//SetBinding
foreach (KeyValuePair kvp in _bindings)
{
factory.SetBinding(kvp.Key, kvp.Value);
}
return dt;
}


private Binding GetBinding(string _path, BindingMode _mode)
{
Binding binding = new Binding();
binding.Path = new PropertyPath(_path);
binding.Mode = _mode;
return binding;
}


You could download the solution from here.
If you use Firefox, you may see strange syntax. If so, try to use IE or just download the source code.

沒有留言: