2016-07-23 7 views
0

Я внедрил IEditableObject для своих ViewModel и элементы управления, привязанные ниже.DataGrid вызывает метод BeginEdit() для запуска дважды

Теперь, когда первый раз я запускаю Window, содержащий эти элементы управления, выполняется метод BeginEdit() и создает резервные копии переменных.

Моя проблема заключается в следующем: Когда я начинаю редактирование DataGrid снова в BeginEdit() пробегов метод и сохраняет изменения в моих уже зарезервированных переменных! Это разрушает цель BeginEdit() и CancelEdit(). Теперь, если я захочу отменить окно, у меня не будет исходных данных. Как я могу это предотвратить?

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

UPDATE:

В настоящем время, я использую немного рубить так:

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

ответ

1

Лучшее не сражаться с элементом управления WPF DataGrid на уровне пользовательского интерфейса. Не записывая свои собственные средства управления, разработанные в соответствии с вашими собственными целями, вы просто не выиграете этот бой. Всегда будет существовать еще одна Microsoft, которая «справится». Я рекомендую реализовать желаемое поведение из безопасного места 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)); 
     } 
    } 

И это простой View, который связывает коллекцию 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> 
+0

Спасибо Jace, я не добавляю и не удаляю что-либо из своей коллекции, только простое редактирование. Как его реализовать? – Vahid

+1

Я ошибся в синтаксисе, но теперь я обновил код. – Jace

+0

Вы можете найти много руководств в Интернете о 'MVVM' и' INotifyPropertyChanged'. Логика добавления и удаления в этом примере будет применяться к элементам при первой загрузке коллекции. Итак, все, что вам нужно сделать, это привязать объект 'ObservableCollection' и заполнить' ExecuteBackupLogic', чтобы определить, что делать, когда какой-либо элемент в вашей коллекции будет изменен. – Jace