注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

天涯倦客的博客

祝福你朋友永远快乐!

 
 
 

日志

 
 

[Silverlight]实现DataGrid使用CheckBox选择行  

2011-09-16 14:51:10|  分类: Silverlight |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
先显示最终结果,其中左边是错误的例子,右边才是正确的
获取 Microsoft Silverlight

在DataGrid中使用CheckBox选择行时典型的错误就是CheckBox没有Binding到任何属性上,这样的话当拖动滚动条时CheckBox.IsChecked就会乱掉,如Demo中左边那个DataGrid所示。最直观的解决方法是禁用DataGrid的滚动条,或者在绑定的数据上添加一个用于绑定CheckBox的bool属性。
其实只要在DataGrid.LoadingRow事件中将CheckBox的DataContext设定为另外一个Object,就不需要牺牲DataGrid的高效能,也不需要改变原有数据的结构。具体实现如下:

MainPage.xaml
<my:MyDataGrid ItemsSource="{Binding}"
AutoGenerateColumns
="False">
<my:MyDataGrid.Columns>
<sdk:DataGridTextColumn Header="Name"
Binding
="{Binding Name}"
Width
="*" />
<sdk:DataGridTextColumn Header="GUID"
Binding
="{Binding GUID}"
Width
="*" />
</my:MyDataGrid.Columns>
</my:MyDataGrid>
MyDataGrid.cs
public class MyDataGrid : DataGrid
{
private const string HeaderCheckBoxName = "select_column_checkbox";

private Dictionary<object, MarkObject> _markObjects;
private DataGridTemplateColumn _selectColumn;
private CheckBox _selectCheckBox;

public MyDataGrid()
{
_markObjects
= new Dictionary<object, MarkObject>();

_selectColumn
= new DataGridTemplateColumn();
_selectColumn.HeaderStyle
= GetHeaderStyle();
_selectColumn.CellTemplate
= GetCellTemplate();
this.Columns.Insert(0, _selectColumn);
this.SizeChanged += new SizeChangedEventHandler(OnSizeChanged);
}

public void SelectAll()
{
if (_selectCheckBox != null)
_selectCheckBox.IsChecked
= true;
SetAllSelectedStates(
true);
}

public void UnselectAll()
{
if (_selectCheckBox != null)
_selectCheckBox.IsChecked
= false;
SetAllSelectedStates(
false);
}

public List<T> GetSelectedItems<T>()
{
List
<T> result = new List<T>();
if (ItemsSource != null)
{
var enu
= ItemsSource.GetEnumerator();
while (enu.MoveNext())
{
if (GetMarkObject(enu.Current).Selected)
result.Add((T)enu.Current);
}
}
return result;
}

protected override void OnLoadingRow(DataGridRowEventArgs e)
{
base.OnLoadingRow(e);

object dataContext = e.Row.DataContext;
FrameworkElement element
= _selectColumn.GetCellContent(e.Row);
element.DataContext
= GetMarkObject(dataContext);
}

private Style GetHeaderStyle()
{
Style style
= new System.Windows.Style();
style.TargetType
= typeof(ContentControl);

StringBuilder tmp
= new StringBuilder();
tmp.Append(
"<DataTemplate ");
tmp.Append(
"xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' ");
tmp.Append(
"xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' >");
tmp.Append(
string.Format("<CheckBox Content='Select All' x:Name='{0}' VerticalAlignment='Center' HorizontalAlignment='Center' />", HeaderCheckBoxName));
tmp.Append(
"</DataTemplate>");
DataTemplate contentTemplate
= XamlReader.Load(tmp.ToString()) as DataTemplate;

style.Setters.Add(
new Setter(ContentControl.ContentTemplateProperty, contentTemplate));
return style;
}

private DataTemplate GetCellTemplate()
{
StringBuilder tmp
= new StringBuilder();
tmp.Append(
"<DataTemplate ");
tmp.Append(
"xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' ");
tmp.Append(
"xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' >");
tmp.Append(
"<CheckBox IsChecked='{Binding Selected,Mode=TwoWay}' VerticalAlignment='Center' HorizontalAlignment='Center' />");
tmp.Append(
"</DataTemplate>");
return XamlReader.Load(tmp.ToString()) as DataTemplate;
}

private MarkObject GetMarkObject(Object obj)
{
if (_markObjects.ContainsKey(obj) == false)
{
MarkObject markObject;
markObject
= new MarkObject();
_markObjects.Add(obj, markObject);
}

return _markObjects[obj];
}

private void OnSizeChanged(object sender, SizeChangedEventArgs e)
{
_selectCheckBox
= this.GetChild<CheckBox>(HeaderCheckBoxName);
if (_selectCheckBox == null)
return;

_selectCheckBox.Checked
+= (sender2, e2) => SetAllSelectedStates(true);
_selectCheckBox.Unchecked
+= (sender2, e2) => SetAllSelectedStates(false);
}

private void SetAllSelectedStates(bool value)
{
if (ItemsSource == null)
return;

var enu
= ItemsSource.GetEnumerator();
while (enu.MoveNext())
{
GetMarkObject(enu.Current).Selected
= value;
}
}




}

其中MarkObject是一个继承INotifyPropertyChanged的类,包含Selected属性,这样更改Selected时可以更新UI。在构造函数中直接插入了个模板列,模板列使用XamlReader.Load(string str)方法直接在代码中创建模板。至于列头的CheckBox则在SizeChanged事件时才可以通过VisualTreeHelper.GetChild递归找到。

欢迎指正。

  评论这张
 
阅读(1527)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017