DataGrid 导致 BeginEdit() 方法 运行 两次

DataGrid causes BeginEdit() method to run twice

我已经为我的 ViewModel 实现了 IEditableObject 并且下面的控件绑定到它。

现在,当我第一次启动包含这些控件的 Window 时,BeginEdit() 方法运行并备份变量。

我的问题是: 当我再次开始编辑 DataGrid 时,BeginEdit() 方法运行并将更改保存到我已经备份的变量中!这破坏了 BeginEdit()CancelEdit() 的目的。现在如果我选择取消Window,我将没有原始数据。我怎样才能避免这种情况?

<ComboBox ItemsSource="{Binding Path=CoatingFactors}"
          SelectedItem="{Binding Path=CoatingFactor}">
</ComboBox>

<DataGrid ItemsSource="{Binding Path=CustomCFactors}"                      
  ....
</DataGrid>

以下是我如何实现 BeginEdit()CancelEdit() 方法:

private List<CustomCFactorItem> customCFactors_ORIGINAL;
private double coatingFactor_ORIGINAL;


public void BeginEdit()
{
    customCFactors_ORIGINAL = customCFactors.ConvertAll(o => o.Clone()).ToList();
    coatingFactor_ORIGINAL = coatingFactor;
}

public void CancelEdit()
{
    customCFactors = customCFactors_ORIGINAL.ConvertAll(o => o.Clone()).ToList();
    coatingFactor = coatingFactor_ORIGINAL;
}

更新:

目前,我正在使用这样的小技巧:

    private List<CustomCFactorItem> customCFactors_ORIGINAL;
    private double coatingFactor_ORIGINAL;

    private int editNum = 0;

    public void BeginEdit()
    {
        if (editNum > 0) return;

        editNum++;

        customCFactors_ORIGINAL = customCFactors.ConvertAll(o => o.Clone());
        coatingFactor_ORIGINAL = coatingFactor;
    }

    public void EndEdit()
    {
        editNum = 0;
    }

    public void CancelEdit()
    {
        editNum = 0;

        customCFactors = customCFactors_ORIGINAL.ConvertAll(o => o.Clone());
        coatingFactor = coatingFactor_ORIGINAL;
    }

最好不要在UI层与WPFDataGrid控件打架。如果不编写自己的控件来满足您自己的目的,您根本不会赢得这场战斗。总会有另一个微软 "gotcha" 需要处理。我建议从 ObservableCollection.

的避风港实施所需的行为
public class ViewModel
{
    public ViewModel()
    {
        CustomCFactors.CollectionChanged += (s, e) => {
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    foreach (CustomCFactorItem item in e.NewItems)
                        item.PropertyChanged += BackupLogicEventHandler;
                    break;
                case NotifyCollectionChangedAction.Remove:
                    foreach (CustomCFactorItem item in e.OldItems)
                        item.PropertyChanged -= BackupLogicEventHandler;
                    break;
            }
        };
        for (int i = 0; i < 10; ++i)
        {
            CustomCFactors.Add(new CustomCFactorItem("one", "two", "three"));
        }
        ExecuteBackupLogic();

    }

    public ObservableCollection<CustomCFactorItem> CustomCFactors { get; set; } = new ObservableCollection<CustomCFactorItem>();

    public void BackupLogicEventHandler(object sender, PropertyChangedEventArgs e){
        ExecuteBackupLogic();
    }
    public void ExecuteBackupLogic()
    {
        Console.WriteLine("changed");
    }
}

下面是 CustomCFactorItem 的示例

public class CustomCFactorItem : INotifyPropertyChanged
    {
        private string _field1 = "";
        public string Field1
        {
            get
            {
                return _field1;
            }
            set
            {
                _field1 = value;
                RaisePropertyChanged("Field1");
            }
        }
        private string _field2 = "";
        public string Field2
        {
            get
            {
                return _field2;
            }
            set
            {
                _field2 = value;
                RaisePropertyChanged("Field2");
            }
        }
        private string _field3 = "";
        public string Field3
        {
            get
            {
                return _field3;
            }
            set
            {
                _field3 = value;
                RaisePropertyChanged("Field1");
            }
        }
        public CustomCFactorItem() { }
        public CustomCFactorItem(string field1, string field2, string field3)
        {
            this.Field1 = field1;
            this.Field2 = field2;
            this.Field3 = field3;
        }
        public event PropertyChangedEventHandler PropertyChanged;
        public void RaisePropertyChanged(string property)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
        }
    }

这是一个将集合绑定到 DataGrid 的简单视图。请注意,每次进行编辑时都会将输出写入控制台。

<Window x:Class="WpfApplication2.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:WpfApplication2"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:ViewModel />
    </Window.DataContext>
    <Grid>
        <DataGrid ItemsSource="{Binding CustomCFactors}" AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Field 1" Binding="{Binding Field1, UpdateSourceTrigger=PropertyChanged}" />
                <DataGridTextColumn Header="Field 2" Binding="{Binding Field2, UpdateSourceTrigger=PropertyChanged}" />
                <DataGridTextColumn Header="Field 3" Binding="{Binding Field3, UpdateSourceTrigger=PropertyChanged}" />
            </DataGrid.Columns>

        </DataGrid>
    </Grid>
</Window>