【问题标题】:ListView: Edit and save SelectedItem with a Button onlyListView:仅使用按钮编辑和保存 SelectedItem
【发布时间】:2018-02-09 17:54:38
【问题描述】:

我有一个绑定在 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 的修改。如果按下“取消”按钮,则应放弃修改。

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

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

你有解决办法吗?

【问题讨论】:

  • 请用英文发表问题
  • 我添加了英语 cmets ;-)
  • 最好删除德语文本,因为它在阅读时会混淆。

标签: c# asp.net button save selecteditem


【解决方案1】:

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

我要设置一个小例子。

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

替代方案

由于您可能从数据库/csv 文件/其他文件中加载数据,因此您应该知道原始值。当按下取消按钮时,您可以在 ViewModel 和订阅 ViewModels 事件并知道原始模型可以在该 viewModel 实例上设置原始值的其他类中调用 CancelButtonClicked 事件,或者只是将 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 的副本。

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

【讨论】:

  • 谢谢 :-) 是的,举个例子让我更容易理解你的意思 :-)
  • 嗯,我想我必须更好地解释我的问题,我会更新它:)
  • 已经编辑了答案,试图解释解决问题的另一种(更简洁)的方法:)我正在创建另一个示例
【解决方案2】:

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

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"/>

【讨论】:

    猜你喜欢
    • 2012-07-15
    • 1970-01-01
    • 1970-01-01
    • 2016-05-10
    • 1970-01-01
    • 2014-10-18
    • 2018-08-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多