如何防止向数据表格中添加项目?

4

我的问题

我正在尝试防止用户在使用内置的.NET DataGrid AddNewItem功能时添加空的DataGrid行。因此,当用户试图提交DataGrid的AddNew事务并将PageItemViewModel.Text留空时,它应该从DataGrid中消失。

代码

ViewModels

public class PageItemViewModel
{
    public string Text { get; set; }
}

public class PageViewModel
{
    public ObservableCollection<PageItemViewModel> PageItems { get; } = new ObservableCollection<PageItemViewModel>();
}

视图

<DataGrid AutoGenerateColumns="True"
          CanUserAddRows="True"
          ItemsSource="{Binding PageItems}" />

我已经尝试过

...在处理以下内容时,从DataGridItemsSource中删除自动创建的对象:

...但总是收到异常,例如:

  • "System.InvalidOperationException: 'Removing' is not allowed during an AddNew or EditItem transaction."
  • "System.InvalidOperationException: 在 CollectionChanged 事件期间不允许更改 ObservableCollection。"
  • "System.InvalidOperationException: ItemsSource 正在使用时无法进行操作。请改用 ItemsControl.ItemsSource 访问和修改元素。"

我的问题

当给定条件为真(在本例中为:String.IsNullOrWhiteSpace(PageItemViewModel.Text) == true)时,如何防止新创建的 PageItemViewModel 被添加到 ObservableCollection<PageItemViewModel> 中。


编辑:

@picnic8: AddingNewItem事件不提供任何形式的RoutedEventArgs,因此没有Handled属性。相反,它是AddingNewItemEventArgs。你的代码无效。

private void DataGrid_AddingNewItem(object sender, AddingNewItemEventArgs e)
{
    var viewModel = (PageItemViewModel)e.NewItem;
    bool cancelAddingNewItem = String.IsNullOrWhiteSpace(viewModel.Text) == true;
    // ??? How can i actually stop it from here?
}

你可以重写 OnItemsChanged - Maria
@MitraM - 在重写的OnItemsChanged方法中修改集合也会导致System.InvalidOperationException: 'Removing' is not allowed during an AddNew or EditItem transaction.异常。 - ˈvɔlə
@Maverik - 创建视图模型非常顺利,没有任何问题。 - ˈvɔlə
@Maverik - 我知道... 但我想要WPF数据网格的功能是有空行来创建新项目。我不想要必须点击按钮才能添加新项目。 - ˈvɔlə
已删除早期的评论 - 意识到这是一个验证问题,而不是一般的预防性问题... 这是我遗漏的一个关键细节。抱歉。 - Maverik
2个回答

6
不能也不应该阻止向基础集合添加新项,因为当最终用户在新行中开始输入时,DataGrid会创建并添加一个新的PageItemViewModel对象,此时它会使用默认值进行初始化。
但是,您可以通过处理DataGrid.RowEditEnding事件,并在DataGridRowEditEndingEventArgs.EditActionDataGridEditAction.Commit时,使用DataGrid.CancelEdit方法有效地删除新对象(或还原现有对象状态)来防止提交该对象,以便在验证失败时。
private void DataGrid_RowEditEnding(object sender, DataGridRowEditEndingEventArgs e)
{
    if (e.EditAction == DataGridEditAction.Commit)
    {
        var bindingGroup = e.Row.BindingGroup;
        if (bindingGroup != null && bindingGroup.CommitEdit())
        {
            var item = (PageItemViewModel)e.Row.Item;
            if (string.IsNullOrWhiteSpace(item.Text))
            {
                e.Cancel = true;
                ((DataGrid)sender).CancelEdit();
            }
        }
    }
}

重要的一点是,RowEditEnding 事件在将当前编辑器的值推送到数据源之前触发,因此您需要在执行验证之前手动完成。我使用 BindingGroup.CommitEdit 方法。

它没有任何问题。非常感谢您,先生。我会尽快用赏金奖励您。 - ˈvɔlə

-1
在您的虚拟机中,订阅AddingNewItem事件并在那里检查您的条件。如果条件失败,您可以停止操作。
var datagrid.AddingNewItem += HandleOnAddingNewItem;

public void HandleOnAddingNewItem(object sender, RoutedEventArgs e)
{
    if(myConditionIsTrue)
    {
        e.Handled = true; // This will stop the bubbling/tunneling of the event
    }
}

修改了我的回答。 - Picnic8
@Picni8,“AddingNewItem”事件不提供任何形式的“RoutedEventArgs”,因此也没有“Handled”属性。相反,它是AddingNewItemEventArgs。你的代码是无效的。 - ˈvɔlə

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接