更改DataGrid时使用MessageBox添加检查 [英] add a check with MessageBox when DataGrid is changed

查看:50
本文介绍了更改DataGrid时使用MessageBox添加检查的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经发布了一个桌面应用程序(因此,我希望得到一个答案,该答案可以将更改和回归测试保持在最低限度),并且在更改网格时需要添加一致性检查CanBeDeleted.

I have a desktop app already released (so I'd appreciate an answer that keeps the changes and regression tests at a minimum) and I need to add a consistency check CanBeDeleted when the grid is changed.

<DataGrid AutoGenerateColumns="False" 
    ItemsSource="{Binding CurrentPosIn.PosInLocationsList}" 
    CanUserAddRows="{Binding UpdateEnabled}" CanUserDeleteRows="{Binding UpdateEnabled}" >

我正在使用UpdateEnabled进行其他操作(配置文件权限),并且我不想将DataGrid设置为只读:我希望(除非它太复杂 ),以查看阻止更改的阻止警报(a MessageBox).

I'm using UpdateEnabled for something different (profile permissions) and I don't want to make the DataGrid read only either: I'd prefer (unless it is too complex) to see a blocking alert (a MessageBox) preventing changes.

到目前为止,我要做的是

What I've done till now is

  1. 与MVVM相对,因为我已将警报放入模型中(但我可以接受,如果它可以使更改变得快速而简单)
  2. 不起作用,因为我的更改的第二部分(如下所示)会产生无效的操作异常

ViewModel包含以下列表

The ViewModel contains the following list

    [Association(ThisKey="Partita", OtherKey="Partita", CanBeNull=true, IsBackReference=true)]
    public ObservableCollection<Model.PosInLocation> posin_locations_list = new  ObservableCollection<Model.PosInLocation>(); 
    public ObservableCollection<PosInLocation> PosInLocationsList {
        get { return posin_locations_list; }
        set { 
            posin_locations_list = value;
            OnPropertyChanged( () => PosInLocationsList );
        }
    } 

我要在此处添加一致性检查

and I'm adding the consistency check here

    string _storage;
    [Column(Name = "storage"), PrimaryKey]
    public string Storage {
        get { return _storage; }
        set { 
            if (this.loadedEF) {
                string validate_msg;
                if (!PurchasePosIn.CanBeDeleted(out validate_msg)) {
                    // against MVVM
                    MessageBox.Show(validate_msg, "Alert", MessageBoxButton.OK); 
                    OnPropertyChanged( () => Storage  );
                    return;
                }
                Persistence.MyContext.deletePosInLocation(this);
            }
            _storage = value;
            OnPropertyChanged( () => Storage  );
            if (this.loadedEF) {
                Persistence.MyContext.insertPosInLocation(this);
            }               
        }
    }

和这里(第二部分)

    internal void posin_locations_list_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs args)
    {                   
        string validate_msg;
        if (!CanBeDeleted(out validate_msg)) {
            // indirectly produces an invalid operation exception 
            MessageBox.Show(validate_msg, "Alert", MessageBoxButton.OK);
            return;
        }
        if (args.OldItems != null)
            foreach(var oldItem in args.OldItems) {
                if ( ((PosInLocation)oldItem).Partita != null)        
                    Persistence.MyContext.deletePosInLocation((PosInLocation)oldItem);              
            }       
        if (args.NewItems != null)
            foreach(var newItem in args.NewItems)
            {
                PosInLocation newPosInLocation = (PosInLocation)newItem;
                if ( newPosInLocation.Partita == null) {
                    newPosInLocation.Partita = this.Partita;
                    newPosInLocation.PurchasePosIn = this;
                    newPosInLocation.loadedEF = true;
                }
             }
    }

推荐答案

如果仅ObservableCollection实现了"previewCollectionChanged",事情将会变得更加容易.

根据您的需要,我建议创建ObservableCollection的子类并重载受保护的方法RemoveItem.
根据您对应用程序的处理方式,您可能想覆盖其他方法,而不仅仅是RemoveItem(例如ClearItems).

当对ObservableCollection进行子类化时,可以覆盖5个受保护的方法:ClearItems,RemoveItem,InsertItem,SetItem和MoveItem.
最后,所有公共方法都将调用这些方法,因此重写它们将使您拥有完全的控制权.

If only the ObservableCollection implemented a "previewCollectionChanged", things would be so much easier.

For your needs I would recommend creating a subclass of ObservableCollection and overloading the protected method RemoveItem.
Depending on what you are doing with your application, you might want to override other methods than just RemoveItem (like ClearItems).

When subclassing ObservableCollection, there are 5 protected methods you can override : ClearItems, RemoveItem, InsertItem, SetItem and MoveItem.
These methods are, in the end, called by all the public methods, so overriding them gives you full control.

这是一个可以运行的小应用程序,它证明了这一点:

Here's a small app you can run that demonstrates this :

public class ObservableCollectionWithDeletionControl<T> : ObservableCollection<T>
{
    public delegate void DeletionDeniedEventHandler(object sender, int indexOfDeniedDeletion);
    public event DeletionDeniedEventHandler DeletionDenied;

    public bool CanDelete { get; set; }

    protected virtual void OnDeletionDenied(int indexOfDeniedDeletion)
    {
        if (DeletionDenied != null) { DeletionDenied(this, indexOfDeniedDeletion); }
    }

    protected override void RemoveItem(int index)
    {
        if (CanDelete)
        {
            base.RemoveItem(index);
        }
        else
        {
            OnDeletionDenied(index);
        }
    }
}

我使用DeletionDenied事件,以便此类不负责显示错误窗口,并使其更可重用.

I use the DeletionDenied event so that this class is not responsible for showing the error window, and it makes it more reusable.

public class MainWindowViewModel
{
    public MainWindow window { get; set; }

    public ObservableCollectionWithDeletionControl<Person> People { get; set; } = new ObservableCollectionWithDeletionControl<Person>();

    public MainWindowViewModel()
    {
        People.DeletionDenied += People_DeletionDenied;
    }

    private void People_DeletionDenied(object sender, int indexOfDeniedDeletion)
    {
        Person personSavedFromDeletion = People[indexOfDeniedDeletion];
        window.displayDeniedDeletion(personSavedFromDeletion.Name);
    }
}

MainWindow的ViewModel.
它知道它是唯一用于显示错误消息的窗口.
(我敢肯定还有比这更好的解决方案,但是我还没有找到在其中显示弹出窗口的简便方法mvvm.)
触发DeletionDenied事件时,将调用错误窗口.

The ViewModel for the MainWindow.
It knows it's window for the sole purpose of displaying the error message.
(I'm sure there's a better solution than this out there but I have yet to find a good and short way of displaying popup windows in mvvm.)
When the DeletionDenied event triggers, the error window is called.

public class Person : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public string Name
    {
        get { return _name; }
        set
        {
            if(_name == value) { return; }
            _name = value;
            if( PropertyChanged != null ) { PropertyChanged(this, new PropertyChangedEventArgs("Name")); }
        }
    }

    private string _name = "";
}


<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WpfApplication1"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">
    <DockPanel>
        <CheckBox DockPanel.Dock="Top" Content="Can delete" IsChecked="{Binding People.CanDelete}" Margin="5" HorizontalAlignment="Left"/>
        <DataGrid ItemsSource="{Binding People}" Margin="5,0"/>
    </DockPanel>
</Window>


public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    public void displayDeniedDeletion(string name)
    {
        TextBox errorMessage = new TextBox();
        errorMessage.Text = string.Format("Cannot delete {0} : access denied !", name);

        Window popupErrorMessage = new Window();
        popupErrorMessage.Content = errorMessage;

        popupErrorMessage.ShowDialog();
    }
}

APP MAIN

public partial class App : Application
{
    private void Application_Startup(object sender, StartupEventArgs e)
    {
        MainWindow window = new MainWindow();
        MainWindowViewModel viewModel = new MainWindowViewModel();

        viewModel.window = window;
        window.DataContext = viewModel;
        window.Show();

        App.Current.MainWindow = window;
    }
}

我已经在启动时设置了ViewModel的窗口,但无论创建ViewModel的位置是什么,您都应该这样做


I've set the ViewModel's window in the startup, but you should probably do it wherever you create your ViewModel


这篇关于更改DataGrid时使用MessageBox添加检查的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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