wpf 如何以 MVVM 友好的方式向 DataGrid 添加新行
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20195808/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to Add a New Row to DataGrid in MVVM Friendly Way
提问by MoonKnight
I have the following DataGrid
我有以下 DataGrid
<DataGrid CanUserDeleteRows="True"
CanUserAddRows="True"
SelectedItem="{Binding SelectedResource, Mode=TwoWay}"
ItemsSource="{Binding Path=Resources, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged,
IsAsync=True}"> ... </<DataGrid>
I am using the MVVM pattern to bind to an ObservableCollection<ResourceViewModel> Resourcesand this works great. I have a button that adds a new row and this is done by adding a new ResourceViewModelto the Resourcescollection - great. Now, I want the user to be able to click on the empty last row, and this automatically creates a new record in the DataGrid.
我正在使用 MVVM 模式绑定到一个ObservableCollection<ResourceViewModel> Resources,这很好用。我有一个按钮,添加一个新行,这是通过添加新做ResourceViewModel的Resources集合-伟大的。现在,我希望用户能够点击空的最后一行,这会自动在DataGrid.
I have made sure the DataGridhas CanUserAddRows=True. I have made sure the class in the collection Resources(ResourceViewModel) that I am binding to has a default constructor (no parameters) and I have made sure the collection type is not readonly. When the user clicks on the last row the default constructor fires but to correctly instantiate the new ResourceViewModelobject in need a reference to either the grid of the Resourcescollection...
我已经确定的DataGrid有CanUserAddRows=True。我已确保我绑定到的集合Resources( ResourceViewModel) 中的类具有默认构造函数(无参数),并且我已确保集合类型不是只读的。当用户单击最后一行时,默认构造函数会触发,但要正确实例化ResourceViewModel需要对Resources集合网格的引用的新对象...
I suppose I could use and AttachedCommandon the CellBeginEditevent and then add a new ResourceViewModelto the observable collection there, is there a standard way of doing this?
我想我可以AttachedCommand在CellBeginEdit事件上使用 and然后在ResourceViewModel那里的可观察集合中添加一个新的,有没有标准的方法来做到这一点?
Note, I have read the following questions and these are of no help to me
请注意,我已阅读以下问题,但这些问题对我没有帮助
Edit. It turns out that I am having problems doing this due to a bug in the WPF DataGrid. See Nigel Spencer's Blog. However, his fix is not working for me at the moment...
编辑。事实证明,由于 WPF 中的错误,我在执行此操作时遇到了问题DataGrid。请参阅Nigel Spencer 的博客。但是,他的修复目前对我不起作用......
采纳答案by Sheridan
As far as I understand, you know how to correctly add new items into your data bound collection to result in a new item being added to the DataGridand your question actually relates to how can you do this when the user clicks on the last row in the DataGrid. The general way to handle some event in the view model is to create an Attached Property(if one does not already exist) that handles that event for you.
据我了解,你知道如何正确地添加新的项目到势必集合导致一个新的项目被添加到你的数据DataGrid,你的问题其实涉及到这一点,你该怎么办时,在最后一行用户点击DataGrid. 在视图模型中处理某些事件的一般方法是创建一个Attached Property(如果尚不存在)为您处理该事件。
For instance, you could create an Attached Propertythat attaches a handler to the relevant event and another of type ICommandwhich you could execute when the event handler is called. Then you could write the functionality of that ICommandin your view model (in which you add a new item to your data bound collection) and data bind your ICommandimplementation to the Attached ICommand Property.
例如,您可以创建一个Attached Property将处理程序附加到相关事件的类型ICommand,以及在调用事件处理程序时可以执行的另一个类型。然后你可以ICommand在你的视图模型中编写它的功能(在其中你向数据绑定集合添加一个新项目)并将你的ICommand实现数据绑定到Attached ICommand Property.
As I'm fairly sure you know how to define Attached Propertys, I won't insult you by showing you. Please let me know if I have misunderstood you, or not made myself clear.
因为我相当确定您知道如何定义Attached Propertys,所以我不会通过向您展示来侮辱您。如果我误解了你,或者没有说明清楚,请告诉我。
回答by James M
Here's an attached property that registers a command for adding rows (assuming the source collection contains a generic type argument):
这是一个附加的属性,用于注册用于添加行的命令(假设源集合包含一个泛型类型参数):
public static readonly DependencyProperty RegisterAddCommandProperty = DependencyProperty.RegisterAttached("RegisterAddCommand", typeof(bool), typeof(DataGridExtensions), new PropertyMetadata(false, OnRegisterAddCommandChanged));
public static bool GetRegisterAddCommand(DependencyObject obj)
{
return (bool)obj.GetValue(RegisterAddCommandProperty);
}
public static void SetRegisterAddCommand(DependencyObject obj, bool value)
{
obj.SetValue(RegisterAddCommandProperty, value);
}
static void OnRegisterAddCommandChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (sender is DataGrid)
{
var DataGrid = sender as DataGrid;
if ((bool)e.NewValue)
DataGrid.CommandBindings.Add(new CommandBinding(AddCommand, AddCommand_Executed, AddCommand_CanExecute));
}
}
public static readonly RoutedUICommand AddCommand = new RoutedUICommand("AddCommand", "AddCommand", typeof(DataGridExtensions));
static void AddCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
var DataGrid = sender as DataGrid;
var ItemsSourceType = DataGrid.ItemsSource.GetType();
var ItemType = ItemsSourceType.GetGenericArguments().Single();
DataGrid.Items.Add(Activator.CreateInstance(ItemType));
}
static void AddCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = (sender as DataGrid).CanUserAddRows;
}
And then you can apply the command to a button somewhere like this:
然后您可以将命令应用到某个按钮,如下所示:
<Button Command="{x:Static Extensions:DataGridExtensions.AddCommand}"/>
Don't forget to specify the command target.
不要忘记指定命令目标。

