您的位置:首页 > 其它

Silverlight中在MVVM模式下对DatagridRow选择控件封装

2014-05-16 15:22 246 查看
  在项目中,凡是涉及到表格的地方用的最多的控件,自然少不了DataGrid的身影,它明了的展示各种数据让人十分喜欢。现在要实现一个功能,使DataGrid具有全选和项选中的功能,如果在传统后台代码中完成这个事情可以说十分简单,但是换到MVVM模式下呢? 不得不面临一个很囧的情况,为了完成UI端CheckBox被选中后能在ViewModel中获取到选中的数据,不得不在在业务实体之外添加一个字段IsChecked 来与我们的数据交互,这样不仅影响美观还影响心情。



  为了实现这一点,无疑需要设置DataGridTemplateColumn的CellTemplate,同时让每一个checkBox拥有这条数据的上下文引用,已方便在当我们选中或反选时能确定数据项,最好的设置时机当然是DataGrid的LoadingRow事件,可以捕获到我们所需要的一切。

  当然,为了实现MVVM,我们需要添加一下附加属性

public static ObservableCollection<object> GetSelectedObjects(DependencyObject obj)
{
return (ObservableCollection<object>)obj.GetValue(SelectedObjectsProperty);
}

public static void SetSelectedObjects(DependencyObject obj, ObservableCollection<object> value)
{
obj.SetValue(SelectedObjectsProperty, value);
}
      
// 用于通知到ViewModel已经被选中的列
public static readonly DependencyProperty SelectedObjectsProperty =
DependencyProperty.RegisterAttached("SelectedObjects", typeof(ObservableCollection<object>), typeof(DataGrid), new PropertyMetadata(new ObservableCollection<object>()));

public static bool GetMonitor(DependencyObject obj)
{
return (bool)obj.GetValue(MonitorProperty);
}

public static void SetMonitor(DependencyObject obj, bool value)
{
obj.SetValue(MonitorProperty, value);
}

// 监视器,用于在DataGrid初始化的时候能有时机注册LoadingRow事件
public static readonly DependencyProperty MonitorProperty =
DependencyProperty.RegisterAttached("Monitor", typeof(bool), typeof(DataGrid), new PropertyMetadata(false, OnMonitorStateChanged));

private static void OnMonitorStateChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
{
var attachedDataGrid = dp as DataGrid;
_attachedDataGrid = attachedDataGrid;
_attachedDataGrid.LoadingRow += (s, ee) =>
{
object dataContext = ee.Row.DataContext;
var elementControl = _attachedDataGrid.Columns[0] as DataGridSelectableColumn;
if (elementControl == null)
throw new InvalidCastException("请将DataGridSelectableColumn放在DataGrid的第一列");
FrameworkElement element = elementControl.GetCellContent(ee.Row);

var elementContext = new SelectableColumnObject() {RowDataContext = new WeakReference( dataContext) };
           //当CheckBox的IsChecked属性值变化之后发生
elementContext.OnChildItemStateChanged += elementContext_OnChildItemStateChanged;
element.DataContext = elementContext;

};
}

static void elementContext_OnChildItemStateChanged(WeakReference rowDataContext, bool obj)
{
_currentColumn.UpdateChildItemSelectedState(rowDataContext, obj);
}


  我将这一列的数据上下文保存到了一个名为RowDataContext的字段中,这样就满足了当选择状态更新时我能知道是那条数据,那么剩下的工作就是列选择和全选状态更新的事件了。Silverlight中DataGrid没有HeaderTemplate,也没有其他事件能够帮助我知道Header的加载,这时候需要借助于xaml,如下

<sdk:DataGridTemplateColumn.HeaderStyle>
<Style TargetType="sdk:DataGridColumnHeader">
<Setter Property="Padding" Value="4" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="sdk:DataGridColumnHeader">
<CheckBox VerticalAlignment="Center"  HorizontalAlignment="Center" VerticalContentAlignment="Center" Content="全选" Loaded="OnHeaderCheckBoxLoaded" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</sdk:DataGridTemplateColumn.HeaderStyle>


  有了这里我们就可以直接在后台代码中定义事件进行处理

private void OnHeaderCheckBoxLoaded(object sender, RoutedEventArgs e)
{
var checkBox = sender as CheckBox;
if (checkBox == null)
return;

checkBox.Loaded -= this.OnHeaderCheckBoxLoaded;
checkBox.Checked += (s2, e2) => this.UpdateAllItemSelectedState(true);
checkBox.Unchecked += (s2, e2) => this.UpdateAllItemSelectedState(false);
}


  到此为止,我们要做的工作基本已经完工,全选状态、行数据的选择状态更新我们做相应处理了。

源码下载:Silverlight下MVVM全选控件_无需额外添加字段.zip
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: