[Silverlight]实现DataGrid使用CheckBox选择行(3)
继续之前的话题。这次的方法仍然和上一次大同小异,只不过改变创建模版列的方法,同时也不在关注那个CheckBox。具体方法就是创建一个UserControl,让它帮我们完成获取DataTemplate和Style,其实这是一种很偷懒的方法,写起来好像也不怎么漂亮。看看下面这段XAML
<UserControl xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
x:Class="DataGridTestLib.DataGridSelectColumnHelper"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DataGridTestLib">
<UserControl.Resources>
<local:MarkObject x:Key="MarkObject" />
<Style TargetType="sdk:DataGridColumnHeader"
x:Name="HeaderStyle">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<CheckBox IsChecked="{Binding Selected,Mode=TwoWay,Source={StaticResource MarkObject}}"
Content="Select All"
VerticalContentAlignment="Center"
VerticalAlignment="Center" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<DataTemplate x:Name="CellTemplate">
<CheckBox IsChecked="{Binding Selected,Mode=TwoWay}"
VerticalAlignment="Center"
HorizontalAlignment="Center" />
</DataTemplate>
</UserControl.Resources>
</UserControl>
x:Class="DataGridTestLib.DataGridSelectColumnHelper"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DataGridTestLib">
<UserControl.Resources>
<local:MarkObject x:Key="MarkObject" />
<Style TargetType="sdk:DataGridColumnHeader"
x:Name="HeaderStyle">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<CheckBox IsChecked="{Binding Selected,Mode=TwoWay,Source={StaticResource MarkObject}}"
Content="Select All"
VerticalContentAlignment="Center"
VerticalAlignment="Center" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<DataTemplate x:Name="CellTemplate">
<CheckBox IsChecked="{Binding Selected,Mode=TwoWay}"
VerticalAlignment="Center"
HorizontalAlignment="Center" />
</DataTemplate>
</UserControl.Resources>
</UserControl>
MarkObject是一个实现INotifyPropertyChanged并且有Selected的类,在这段XAML中,MarkObject的Selected与HeaderStyle中的CheckBox.IsChecked双向绑定,我们只需要操作这个MarkObject的Selected属性就可以控制DataGrid的全选功能。如果看过UserControl中自动生成的InitializeComponent()方法会发现Resource中有Name的DependancyObject都已经成为这个UserControl的internal属性,但注意MarkObject不是DependancyObject,所以要通过这段代码获取这个MarkObject
this.MarkObject = this.Resources["MarkObject"] as MarkObject;
最后只要和上次一样创建一个DataGridColumn,通过它操作全选功能就可以了。

public class DataGridSelectColumn2 : DataGridTemplateColumn
{
private Dictionary<object, MarkObject> _markObjects;
private MarkObject _markObject;
private DataGrid _ownerDataGrid;
public DataGridSelectColumn2()
{
IsReadOnly = true;
_markObjects = new Dictionary<object, MarkObject>();
DataGridSelectColumnHelper helper = new DataGridSelectColumnHelper();
this.HeaderStyle = helper.HeaderStyle;
this.CellTemplate = helper.CellTemplate;
_markObject = helper.MarkObject;
_markObject.PropertyChanged += (sender, e) =>
{
if (_markObject.Selected)
SelecteAll();
else
UnselectAll();
};
}
public DataGrid OwnerDataGrid
{
get
{
return _ownerDataGrid;
}
set
{
_ownerDataGrid = value;
_ownerDataGrid.LoadingRow += OnDataGridLoadingRow;
}
}
private void OnDataGridLoadingRow(object sender, DataGridRowEventArgs e)
{
object dataContext = e.Row.DataContext;
FrameworkElement element = this.GetCellContent(e.Row);
element.DataContext = GetMarkObject(dataContext);
}
private void SetAllSelectedStates(bool value)
{
if (OwnerDataGrid.ItemsSource == null)
return;
var enu = OwnerDataGrid.ItemsSource.GetEnumerator();
while (enu.MoveNext())
{
GetMarkObject(enu.Current).Selected = value;
}
}
private MarkObject GetMarkObject(Object obj)
{
if (_markObjects.ContainsKey(obj) == false)
{
MarkObject markObject;
markObject = new MarkObject();
_markObjects.Add(obj, markObject);
}
return _markObjects[obj];
}
public void SelecteAll()
{
_markObject.Selected = true;
SetAllSelectedStates(true);
}
public void UnselectAll()
{
_markObject.Selected = false;
SetAllSelectedStates(false);
}
public List<T> GetSelectedItems<T>()
{
List<T> result = new List<T>();
if (OwnerDataGrid.ItemsSource != null)
{
var enu = OwnerDataGrid.ItemsSource.GetEnumerator();
while (enu.MoveNext())
{
if (GetMarkObject(enu.Current).Selected)
result.Add((T)enu.Current);
}
}
return result;
}
}
{
private Dictionary<object, MarkObject> _markObjects;
private MarkObject _markObject;
private DataGrid _ownerDataGrid;
public DataGridSelectColumn2()
{
IsReadOnly = true;
_markObjects = new Dictionary<object, MarkObject>();
DataGridSelectColumnHelper helper = new DataGridSelectColumnHelper();
this.HeaderStyle = helper.HeaderStyle;
this.CellTemplate = helper.CellTemplate;
_markObject = helper.MarkObject;
_markObject.PropertyChanged += (sender, e) =>
{
if (_markObject.Selected)
SelecteAll();
else
UnselectAll();
};
}
public DataGrid OwnerDataGrid
{
get
{
return _ownerDataGrid;
}
set
{
_ownerDataGrid = value;
_ownerDataGrid.LoadingRow += OnDataGridLoadingRow;
}
}
private void OnDataGridLoadingRow(object sender, DataGridRowEventArgs e)
{
object dataContext = e.Row.DataContext;
FrameworkElement element = this.GetCellContent(e.Row);
element.DataContext = GetMarkObject(dataContext);
}
private void SetAllSelectedStates(bool value)
{
if (OwnerDataGrid.ItemsSource == null)
return;
var enu = OwnerDataGrid.ItemsSource.GetEnumerator();
while (enu.MoveNext())
{
GetMarkObject(enu.Current).Selected = value;
}
}
private MarkObject GetMarkObject(Object obj)
{
if (_markObjects.ContainsKey(obj) == false)
{
MarkObject markObject;
markObject = new MarkObject();
_markObjects.Add(obj, markObject);
}
return _markObjects[obj];
}
public void SelecteAll()
{
_markObject.Selected = true;
SetAllSelectedStates(true);
}
public void UnselectAll()
{
_markObject.Selected = false;
SetAllSelectedStates(false);
}
public List<T> GetSelectedItems<T>()
{
List<T> result = new List<T>();
if (OwnerDataGrid.ItemsSource != null)
{
var enu = OwnerDataGrid.ItemsSource.GetEnumerator();
while (enu.MoveNext())
{
if (GetMarkObject(enu.Current).Selected)
result.Add((T)enu.Current);
}
}
return result;
}
}
记得IsReadOnly = true。
推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架