我正在使用WPF数据网格,并且SelectionUnit =“Cell”和SelectionMode =“Extended”。我也尽可能地坚持MVVM主体。
我需要我的ViewModel来跟踪当前的SelectedCells。
如果我可以将其SelectedCells属性绑定到我的ViewModel,那么生活将很容易。奇怪的是,当我们第一次选择网格中的任何单元格时,SelectedCells只会被提升一次。
MS在此解释:http://social.msdn.microsoft.com/Forums/en/wpf/thread/737117f4-6d20-4232-88cf-e52cc44d4431
有人能想到一种MVVM友好的解决方法吗?
谢谢!
答案 0 :(得分:11)
我意识到我的最后一个答案是针对SelectedItems而不是SelectedCells,所以我写了一个完整的附加属性类来为多个SelectedCells做数据绑定,其工作原理如下:
<controls:DataGrid ItemsSource="{StaticResource list}"
SelectionMode="Extended"
behaviors:DataGridSelectedCellsBehavior.SelectedCells="{Binding Path=SelectedGridCellCollection, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
我有一个有效的源代码和一个演示项目here。
附加财产行为代码:
public class DataGridSelectedCellsBehavior
{
// Source : https://archive.codeplex.com/?p=datagridthemesfromsl
// Credit to : T. Webster, https://stackoverflow.com/users/266457/t-webster
public static IList<DataGridCellInfo> GetSelectedCells(DependencyObject obj)
{
return (IList<DataGridCellInfo>)obj.GetValue(SelectedCellsProperty);
}
public static void SetSelectedCells(DependencyObject obj, IList<DataGridCellInfo> value)
{
obj.SetValue(SelectedCellsProperty, value);
}
public static readonly DependencyProperty SelectedCellsProperty = DependencyProperty.RegisterAttached("SelectedCells", typeof(IList<DataGridCellInfo>), typeof(DataGridSelectedCellsBehavior), new UIPropertyMetadata(null, OnSelectedCellsChanged));
static SelectedCellsChangedEventHandler GetSelectionChangedHandler(DependencyObject obj)
{
return (SelectedCellsChangedEventHandler)obj.GetValue(SelectionChangedHandlerProperty);
}
static void SetSelectionChangedHandler(DependencyObject obj, SelectedCellsChangedEventHandler value)
{
obj.SetValue(SelectionChangedHandlerProperty, value);
}
static readonly DependencyProperty SelectionChangedHandlerProperty = DependencyProperty.RegisterAttached("SelectedCellsChangedEventHandler", typeof(SelectedCellsChangedEventHandler), typeof(DataGridSelectedCellsBehavior), new UIPropertyMetadata(null));
//d is MultiSelector (d as ListBox not supported)
static void OnSelectedCellsChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
{
if (GetSelectionChangedHandler(d) != null)
return;
if (d is DataGrid)//DataGrid
{
DataGrid datagrid = d as DataGrid;
SelectedCellsChangedEventHandler selectionchanged = null;
foreach (var selected in GetSelectedCells(d) as IList<DataGridCellInfo>)
datagrid.SelectedCells.Add(selected);
selectionchanged = (sender, e) =>
{
SetSelectedCells(d, datagrid.SelectedCells);
};
SetSelectionChangedHandler(d, selectionchanged);
datagrid.SelectedCellsChanged += GetSelectionChangedHandler(d);
}
//else if (d is ListBox)
//{
// ListBox listbox = d as ListBox;
// SelectionChangedEventHandler selectionchanged = null;
// selectionchanged = (sender, e) =>
// {
// SetSelectedCells(d, listbox.SelectedCells);
// };
// SetSelectionChangedHandler(d, selectionchanged);
// listbox.SelectionChanged += GetSelectionChangedHandler(d);
//}
}
}
查看型号代码:
class DemoViewModel : INotifyPropertyChanged
{
private IList<DataGridCellInfo> selectedGridCellCollection = new List<DataGridCellInfo>();
public IList<DataGridCellInfo> SelectedGridCellCollection
{
get { return selectedGridCellCollection; }
set
{
selectedGridCellCollection = value;
NotifyPropertyChanged();
}
}
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
答案 1 :(得分:2)
您是否需要经常数据绑定的SelectedCells,或者只是当用户点击OK / Accept按钮时?例如,如果您在用户所处的任何进程结束时只需要它,则可以将SelectedCells绑定到Button的CommandParameter属性。 SelectedCells是一个IList,你知道只需要对选择实际上的任何对象类型进行强制转换。另一个选项比较混乱,您可以使用附加属性,将事件处理保留在视图之外。此附加属性将处理ListBox或在您的情况下处理DataGrid(MultiSelector)。
public class Attach
{
public static IList GetSelectedItems(DependencyObject obj)
{
return (IList)obj.GetValue(SelectedItemsProperty);
}
public static void SetSelectedItems(DependencyObject obj, IList value)
{
obj.SetValue(SelectedItemsProperty, value);
}
/// <summary>
/// Attach this property to expose the read-only SelectedItems property of a MultiSelector for data binding.
/// </summary>
public static readonly DependencyProperty SelectedItemsProperty =
DependencyProperty.RegisterAttached("SelectedItems", typeof(IList), typeof(Attach), new UIPropertyMetadata(new List<object>() as IList, OnSelectedItemsChanged));
static SelectionChangedEventHandler GetSelectionChangedHandler(DependencyObject obj)
{
return (SelectionChangedEventHandler)obj.GetValue(SelectionChangedHandlerProperty);
}
static void SetSelectionChangedHandler(DependencyObject obj, SelectionChangedEventHandler value)
{
obj.SetValue(SelectionChangedHandlerProperty, value);
}
static readonly DependencyProperty SelectionChangedHandlerProperty =
DependencyProperty.RegisterAttached("SelectionChangedHandler", typeof(SelectionChangedEventHandler), typeof(Attach), new UIPropertyMetadata(null));
//d is MultiSelector (d as ListBox not supported)
static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
{
if (GetSelectionChangedHandler(d) != null)
return;
if (d is MultiSelector)//DataGrid
{
MultiSelector multiselector = d as MultiSelector;
SelectionChangedEventHandler selectionchanged = null;
foreach (var selected in GetSelectedItems(d) as IList)
multiselector.SelectedItems.Add(selected);
selectionchanged = (sender, e) =>
{
SetSelectedItems(d, multiselector.SelectedItems);
};
SetSelectionChangedHandler(d, selectionchanged);
multiselector.SelectionChanged += GetSelectionChangedHandler(d);
}
else if (d is ListBox)
{
ListBox listbox = d as ListBox;
SelectionChangedEventHandler selectionchanged = null;
selectionchanged = (sender, e) =>
{
SetSelectedItems(d, listbox.SelectedItems);
};
SetSelectionChangedHandler(d, selectionchanged);
listbox.SelectionChanged += GetSelectionChangedHandler(d);
}}}
XAML中的用法:
<DataGrid ItemsSource="{Binding Path=SourceList}"
myControls:Attach.SelectedItems="{Binding Path=myMvvmSelectedItems, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectionMode="Extended" />
答案 2 :(得分:1)
您可能对 WPF Application Framework (WAF) 的 BookLibrary 示例应用感兴趣。它显示了如何将DataGrid.SelectedItems与ViewModel同步。这可能与SelectedCells非常相似。
答案 3 :(得分:0)
完美的MVVM绑定和完整的事件处理程序代码隐藏之间存在交互性的灰色区域EventTriggers(请参阅Blend SDK):)
如果你将一个eventtrigger放到datagrid,并设置为“SelectionChanged”并将eventargs传递给一个命令(使用EventToCommand actiontrigger),你可以从eventargs中获取所选的项目希望...
或者使用MS线程中所述的多重绑定:)