如何以MVVM友好的方式向DataGrid添加新行

时间:2013-11-25 14:39:46

标签: c# wpf mvvm datagrid

我有以下DataGrid

<DataGrid CanUserDeleteRows="True" 
          CanUserAddRows="True"
          SelectedItem="{Binding SelectedResource, Mode=TwoWay}"
          ItemsSource="{Binding Path=Resources, Mode=TwoWay,
                                UpdateSourceTrigger=PropertyChanged, 
                                IsAsync=True}"> ... </<DataGrid>

我正在使用MVVM模式绑定到ObservableCollection<ResourceViewModel> Resources,这很有用。我有一个添加新行的按钮,这是通过向ResourceViewModel集合添加新Resources来完成的 - 很棒。现在,我希望用户能够点击空的最后一行,这会自动在DataGrid中创建一条新记录。

我确保DataGridCanUserAddRows=True。我确保我绑定的集合ResourcesResourceViewModel)中的类具有默认构造函数(无参数),并确保集合类型不是只读的。当用户单击最后一行时,默认构造函数将触发,但要正确实例化需要的新ResourceViewModel对象,请引用Resources集合的网格...

我想我可以在AttachedCommand事件中使用CellBeginEdit,然后在那里的可观察集合中添加一个新的ResourceViewModel是否有标准的方法来执行此操作?


请注意,我已阅读以下问题,这些对我没有帮助

  1. WPF DataGrid - Event for New Rows?
  2. How to add rows with a DataGrid and MVVM

  3. 编辑。事实证明,由于WPF DataGrid中的错误,我在执行此操作时遇到了问题。见Nigel Spencer's Blog。但是,他的修复目前对我不起作用......

2 个答案:

答案 0 :(得分:3)

据我了解,您知道如何正确地将新项目添加到数据绑定集合中,以便将新项目添加到DataGrid,并且您的问题实际上与您如何在用户点击DataGrid中的最后一行。在视图模型中处理某个事件的一般方法是创建一个Attached Property(如果尚不存在),为您处理该事件。

例如,您可以创建一个Attached Property,它将处理程序附加到相关事件,另一个类型ICommand可以在调用事件处理程序时执行。然后,您可以在视图模型中编写ICommand的功能(在其中向数据绑定集合中添加新项),数据将ICommand实现绑定到Attached ICommand Property。< / p>

由于我很确定你知道如何定义Attached Property,我不会通过向你展示来侮辱你。如果我误解了你,或者没有让自己明白,请告诉我。

答案 1 :(得分:1)

这是一个附加属性,用于注册添加行的命令(假设源集合包含泛型类型参数):

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;
}

然后你可以将命令应用到这样的按钮:

<Button Command="{x:Static Extensions:DataGridExtensions.AddCommand}"/>

不要忘记指定命令目标。