ListView:仅使用 Button 编辑和保存 SelectedItem

ListView: Edit and save SelectedItem with a Button only

我有一个绑定在 ObservableCollection 上的 ListView。

<ListView Grid.Column="0" Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" BorderThickness="0" Margin="5" Name="CustomerListView" ItemsSource="{Binding Customers}" SelectedItem="{Binding Path=CurrentCustomer,  Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <WrapPanel>
                 <TextBlock Text="{Binding FirstName}"/>
                 <TextBlock Margin="5,0,0,0" Text="{Binding LastName}"/>
            </WrapPanel>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

在同一个视图中,我有一些用于编辑 CurrentCustomer 的文本框。我还有一个保存按钮。如果单击此按钮,则应保存对 CurrentCustomer 的修改。如果按下按钮 "cancel",修改应该被丢弃。

<TextBox Name="CustomerSalutationTextBox" Grid.Column="1" Grid.Row="0" Height="20px" Margin="5" Text="{Binding Path=CurrentCustomer.Salutation, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>

问题是,如果我对 currentCusomer 进行一些更改,它们会立即生效。

你有解决办法吗?

您需要在您的 ViewModel 中添加的内容/您具有绑定上下文的 class 是保存文本字段中之前的内容。 当你点击中止时,你只需用旧值覆盖你的新值。

我要设置一个小例子。

  class ExampleViewModel : INotifyPropertyChanged {
    private string _customerLastName;
    private string _customerName;
    private string _initialCustomerName;
    private string _initialCustomerLastName;

    public string CustomerName {
      get { return this._customerName; }
      set {
        this._customerName = value;
        this.OnPropertyChanged();
      }
    }

    public string CustomerLastName {
      get { return this._customerLastName; }
      set {
        this._customerLastName = value;
        this.OnPropertyChanged();
      }
    }

    public ExampleViewModel(string customerName, string customerLastName) {
      this.CustomerName = customerName;
      this.CustomerLastName = customerLastName;
      this._initialCustomerName = customerName;
      this._initialCustomerLastName = customerLastName;
    }

    //example event handler for your abort button
    private void OnAbortButtonClick(object sender, EventArgs args) {
      this.CustomerName = this._initialCustomerName; //set the initial name
      this.CustomerLastName = this._initialCustomerLastName; //set the initial lastName
    }

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
      this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
  }

备选

由于您可能从 database/csv file/something 其他地方加载数据,因此您应该知道原始值。按下取消按钮时,您可以在 ViewModel 和其他订阅 ViewModels 事件的 class 中调用 CancelButtonClicked 事件,并且知道原始模型可以在该 viewModel 实例上设置原始值,或者只是交换 ViewModel 实例与原来的。

看看:https://msdn.microsoft.com/en-us/library/hh848246.aspx

  class ExampleViewModel : INotifyPropertyChanged {
    private string _customerLastName;
    private string _customerName;

    public event CancelButtonClicked CancelButtonClicked;

    public string CustomerName {
      get { return this._customerName; }
      set {
        this._customerName = value;
        this.OnPropertyChanged();
      }
    }

    public string CustomerLastName {
      get { return this._customerLastName; }
      set {
        this._customerLastName = value;
        this.OnPropertyChanged();
      }
    }

    public ExampleViewModel(string customerName, string customerLastName) {
      this.CustomerName = customerName;
      this.CustomerLastName = customerLastName;
    }

    private void OnAbortButtonClick(object sender, EventArgs args) {

    }

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
      this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
  }

  internal delegate void CancelButtonClicked(object sender);

  public class SomeOtherClass {
    private ExampleViewModel _viewModel;

    public SomeOtherClass() {
      this._viewModel = new ExampleViewModel("foo", "bar");
      this._viewModel.CancelButtonClicked += ViewModelOnCancelButtonClicked;
    }

    private void ViewModelOnCancelButtonClicked(object sender) {
      ExampleViewModel vm = sender as ExampleViewModel;
      vm.CustomerName = "foo"; //set the initial values again
      vm.CustomerLastName = "bar";
    }
  }

备选方案2

您还可以在调用取消按钮的事件以恢复其原始状态时交换完整的 VM。

备选方案3

每次您的 SelectedItem 更改时,您都可以通过创建它的副本来保存它的当前状态。按下 CancelButton 时,将 SelectedItem 设置为原始 viewModel 的副本。

为此,您需要复制构造函数或复制方法。

我找到了另一个解决方案。在视图后面的代码中,我添加了以下内容:

void saveButton_Click(object sender, RoutedEventArgs e)
{
    BindingExpression be = customerFirstNameTextBox.GetBindingExpression(TextBox.TextProperty);
    be.UpdateSource();
}

我的带有 UpdateSourceTrigger Explicit 的文本框

<TextBox Name="customerFirstNameTextBox" Grid.Column="1" Grid.Row="2" Height="20px" Margin="5" Text="{Binding Path=CurrentCustomer.FirstName, Mode=TwoWay, UpdateSourceTrigger=Explicit}" IsEnabled="{Binding Path=IsCustomerTextEnabled}"/>

还有我的按钮

<Button Name="SaveButton" Click="saveButton_Click" Margin="5" Content="Save"/>