WPF DataGrid删除IEditableCollectionView.CancelNew()上的NewItemPlaceholder [英] WPF DataGrid removing NewItemPlaceholder on IEditableCollectionView.CancelNew()

查看:99
本文介绍了WPF DataGrid删除IEditableCollectionView.CancelNew()上的NewItemPlaceholder的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

概述



我正在开发WPF应用程序(使用.NET 4.5),其中一部分涉及在DataGrid中显示一些数据。

用户可以在DataGrid中添加新行,并可以通过其他位置的按钮将其删除。



当用户开始添加无法提交的新行然后按删除按钮时,我遇到了一个问题。

新行应为

但是,DataGrid的 NewItemPlaceholder 行被删除,并且从此不再显示。



我已经完成了示例项目
此处也是简短的录像。 br>
是示例应用程序的外观。



要重现:


  1. 双击最上方一行的价格单元格

  2. 输入无效的数字以通过异常触发验证

  3. (可选)选择另一行

  4. 单击删除按钮



  5. 代码



    viewmodel在ObservableCollection中获取数据,该数据用作集合视图的源。
    我有一个简单的命令连接到删除按钮。如果用户要添加项目( IEditableCollectionView.IsAddingNew ),则尝试使用 .CancelNew()取消操作collectionView。但是,命令完成后,DataGrid的 NewItemPlaceholder 被删除了。



    到目前为止,我已经尝试了: / p>


    • 触发DataGrid ,通过设置 dataGrid.CanUserAddRows = true 使占位符再次出现,从而可以解决此问题,但是

    • 从源集合中删除无效的项目: this.productsObservable.Remove(this.Products .CurrentAddItem作为产品)

      这不会改变行为,仍会删除占位符。

    • 从集合视图: this.Products.Remove(this.Products.CurrentAddItem)

      这引发一个异常,这很有意义:不允许删除 d



    还有另一种方法可以取消用户的添加



    在示例项目中,为了简化起见,我正在实例化VM构造函数中的数据。

    在现实中,我正在使用对服务的异步调用,将结果包装在ObservableCollection中,并且ViewModel实现了INotifyPropertyChanged。业务对象没有实现INPC。



    示例项目的XAML:

     < Window x:Class = WpfApplication3.MainWindow 
    xmlns = http://schemas.microsoft.com/winfx/2006/xaml/presentation
    xmlns:x = http://schemas.microsoft.com/winfx/2006/xaml
    xmlns:local = clr-namespace:WpfApplication3
    Title = MainWindow Height = 250>
    < Window.DataContext>
    < local:ViewModel />
    < /Window.DataContext>

    < StackPanel Orientation = Vertical>
    < Button Command = {Binding DeleteCommand} Content =删除行 />
    < DataGrid
    ItemsSource = {Binding Products}
    CanUserDeleteRows = False
    CanUserAddRows = True
    SelectionMode = Single>
    < / DataGrid>
    < / StackPanel>
    < / Window>

    ViewModel,以及一个简单的业务对象:

     使用系统; 
    使用System.Collections.ObjectModel;
    使用System.ComponentModel;
    使用System.Linq;
    使用System.Windows.Data;
    使用System.Windows.Input;

    命名空间WpfApplication3
    {
    公共类ViewModel
    {
    private只读ObservableCollection< Product>可观察到的产品;

    public ViewModel()
    {
    this.productsObservable = new ObservableCollection< Product>()
    {
    new Product(){名称=白色巧克力,价格= 1},
    新产品(){名称=黑巧克力,价格= 2},
    新产品(){名称=热巧克力,价格= 3},
    };

    this.Products = CollectionViewSource.GetDefaultView(this.productsObservable)as IEditableCollectionView;
    this.Products.NewItemPlaceholderPosition = NewItemPlaceholderPosition.AtBeginning;

    this.DeleteCommand = new DelegateCommand(this.OnDeleteCommandExecuted);
    }

    public ICommand DeleteCommand {get;私人套装; }
    公共IEditableCollectionView产品{私人套装; }

    私人无效OnDeleteCommandExecuted()
    {
    if(this.Products.IsAddingNew)
    {
    this.Products.CancelNew();
    }
    }

    }

    公共类产品
    {
    公共字符串名称{get;组; }
    公众十进制价格{组; }
    }
    }


    解决方案

    怎么办呢?

      private void OnDeleteCommandExecuted()
    {
    if(this.Products.IsAddingNew)
    {
    this.Products.CancelNew();
    this.Products.AddNew();
    }
    }

    您仍然会删除输入错误的行,但您将添加一个新的(主要是)空行。唯一的问题(尽管我确定它可以修复)是,您在数字列中获得默认的 0 值,而不是 null


    Overview

    I'm developing a WPF application (using .NET 4.5), part of which involves showing some data in a DataGrid.
    The user has the ability to add a new row inside the DataGrid and delete one via a button elsewhere.

    I have an issue when the user starts adding a new row that cannot be committed and then presses the delete button.
    The new row should be canceled and the DataGrid reset to its previous state.
    However, the DataGrid's NewItemPlaceholder row is deleted and never shown again.

    I've made a sample project that demonstrates the issue.
    Here is a short screencast as well.
    This is what the sample app looks like.

    To reproduce:

    1. Double click the Price cell on the topmost row
    2. Enter an invalid number to trigger validation via an exception
    3. (optional) Select another row
    4. Click the delete button

    Code

    The viewmodel gets the data in an ObservableCollection, which is used as the source for a collection view. I have a simple command wired to the delete button. If the user is adding an item (IEditableCollectionView.IsAddingNew) I try to cancel the operation using .CancelNew() on the collectionView. However, when the command completes the DataGrid has its NewItemPlaceholder deleted.

    So far, I've tried:

    • Triggering the DataGrid to make the placeholder appear again by setting dataGrid.CanUserAddRows = true, which fixes the issue somewhat, but that's a horrible workaround and it's buggy, afterwards the placeholder is not editable.
    • Removing the invalid item from the source collection: this.productsObservable.Remove(this.Products.CurrentAddItem as Product).
      This doesn't change the behavior, the placeholder is still removed.
    • Removing the item from the collection view: this.Products.Remove(this.Products.CurrentAddItem).
      This throws an exception, which makes sense: 'Remove' is not allowed during an AddNew or EditItem transaction.

    Is there another way I can cancel the user's add AND have the NewItemPlaceholder showing?

    In the sample project I'm instantiating the data inside the VM constructor for simplicity.
    In reality I'm using async calls to a service, wrapping the result in ObservableCollection and the ViewModel implements INotifyPropertyChanged. The business object doesn't implement INPC.

    XAML for the sample project:

    <Window x:Class="WpfApplication3.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfApplication3"
            Title="MainWindow" Height="250">
        <Window.DataContext>
            <local:ViewModel />
        </Window.DataContext>
    
        <StackPanel Orientation="Vertical">
            <Button Command="{Binding DeleteCommand}" Content="Delete row" />
            <DataGrid
                ItemsSource="{Binding Products}"
                CanUserDeleteRows="False"
                CanUserAddRows="True"
                SelectionMode="Single">
            </DataGrid>
        </StackPanel>
    </Window>
    

    ViewModel, together with a simple Business Object:

    using System;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Linq;
    using System.Windows.Data;
    using System.Windows.Input;
    
    namespace WpfApplication3
    {
        public class ViewModel
        {
            private readonly ObservableCollection<Product> productsObservable;
    
            public ViewModel()
            {
                this.productsObservable = new ObservableCollection<Product>()
                {
                    new Product() { Name = "White chocolate", Price = 1},
                    new Product() { Name = "Black chocolate", Price = 2},
                    new Product() { Name = "Hot chocolate", Price = 3},
                };
    
                this.Products = CollectionViewSource.GetDefaultView(this.productsObservable) as IEditableCollectionView;
                this.Products.NewItemPlaceholderPosition = NewItemPlaceholderPosition.AtBeginning;
    
                this.DeleteCommand = new DelegateCommand(this.OnDeleteCommandExecuted);
            }
    
            public ICommand DeleteCommand { get; private set; }
            public IEditableCollectionView Products { get; private set; }
    
            private void OnDeleteCommandExecuted()
            {
                if (this.Products.IsAddingNew)
                {
                    this.Products.CancelNew();
                }
            }
    
        }
    
        public class Product
        {
            public string Name { get; set; }
            public decimal Price { get; set; }
        }
    }  
    

    解决方案

    What about this:

    private void OnDeleteCommandExecuted()
    {
        if (this.Products.IsAddingNew)
        {
            this.Products.CancelNew();
            this.Products.AddNew();
        }
    }
    

    You'll still delete the row with the bad input, but you'll add a new (mostly) empty row. The only problem, although I'm sure its fixable, is that you get the default 0 value in the numerical column not a null.

    这篇关于WPF DataGrid删除IEditableCollectionView.CancelNew()上的NewItemPlaceholder的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆