繁体   English   中英

对于绑定到列表框的 SelectedItem 的对象实例,如何捕获 PropertyChanged 事件

[英]How to catch PropertyChanged event, for an object instance that is bound to the SelectedItem of a listbox

我正在尝试用 C# 学习 WPF,所以如果这个问题很幼稚,请耐心等待。

  1. 我有一个名为 Person 的类,它有 2 个属性(FirstName、LastName)和 1 个实现 INotifyPropertyChanged 的​​计算属性(FullName)。
  2. 我有一个 Person 类型的 ObservableCollection,我已经将它绑定到了一个 ListBox。
  3. 我有一个名为 SelectedPerson 的 Person 实例,我已将其绑定到 ListBox SelectedItem 属性。
  4. 我有两个文本框,它们绑定到 SelectedPerson.FullName 和 SelectedPerson.LastName 属性。

到目前为止,一切正常:

  • 单击(选择)一个人从 ListBox 更新 SelectedPerson 实例,这反过来用正确的信息填充 TextBoxes
  • 更改任一 TextBox 内容会更新 SelectedPerson 实例,这反过来会更新 ListBox 的内容(当编辑的 TextBox 失去焦点时)

我现在想要实现的是以某种方式侦听 SelectedPerson 的 PropertyChanged 事件,因此在更改 TextBox 的内容后,我可以运行一些代码。 我希望代码在更改绑定属性后运行一次(例如编辑停止后 ListBox 的更新方式),所以我真的不想听 TextBox 的 TextChanged 事件。

我可以使用 SelectedPerson 的 PropertyChanged 事件,所以无论当前 SelectedItem 是哪个 Person 我都可以监听 PropertyChanged 事件,还是必须对 ObservableCollection 中的每个 Person 实例使用 PropertyChanged 事件? (或者……不同的东西?)

作为参考,这里是上述所有代码的相关摘录

人物类

  public class Person : INotifyPropertyChanged
    {
       ...
       public string FirstName
        {
            get { return _firstName; }
            set { _firstName = value; OnPropertyChanged("FirstName"); OnPropertyChanged("FullName"); }
        }

        public string LastName
        {
            get { return _lastName; }
            set { _lastName = value; OnPropertyChanged("LastName"); OnPropertyChanged("FullName"); }
        }

        public string FullName { get { return $"{LastName} {FirstName}"; } }
    }

主窗口

public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public ObservableCollection<Person> People { get; set; }

        private Person _selectedPerson;
        public Person SelectedPerson
        {
            get { return _selectedPerson; }
            set { _selectedPerson = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedPerson"));  }
        }

        public MainWindow() 
        {
            InitializeComponent();
            this.DataContext = this;
            People = new ObservableCollection<Person>
            {
                new Person { FirstName = "John", LastName = "Doe" },
                new Person { FirstName = "Jane", LastName = "Smith" }
            };
        }
    }

和 XAML 项目

...
        <ListBox Grid.Row="1" Grid.Column="1" ItemsSource="{Binding Path=People}" SelectedItem="{Binding SelectedPerson, Mode=TwoWay}" DisplayMemberPath="FullName" Margin="10"/>
        <StackPanel Grid.Row="1" Grid.Column="2" Orientation="Vertical" Margin="10" VerticalAlignment="Center">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="First Name" HorizontalAlignment="Right" Margin="10"/>
                <TextBox Text="{Binding SelectedPerson.FirstName, Mode=TwoWay}" Width="120" Margin="10"/>
            </StackPanel>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="Last Name" HorizontalAlignment="Right" Margin="10"/>
                <TextBox Text="{Binding SelectedPerson.LastName, Mode=TwoWay}" Width="120" Margin="10"/>
            </StackPanel>
        </StackPanel>
...

更改TextBox ,将运行其绑定的属性设置器。 即运行 FirstName.set 或 LastName.set。 你当然知道这一点。 您还可以从 setter 运行额外的代码,该代码仅在TextBox更改时运行。 为防止多次运行您的代码,请根据支持字段值检查新值,如果匹配,则返回。

我可以使用SelectedPerson的PropertyChanged事件吗,所以无论哪个Person是当前SelectedItem我都可以监听PropertyChanged事件

是的。 但是,你需要添加代码认购(“听”)到PropertyChanged你的活动MainWindow ,这样就可以在这个变化的响应SelectedPerson属性值。 也就是说,当该属性值更改时,您需要取消订阅先前设置的Person对象的PropertyChanged事件,并订阅现在设置的Person对象上的事件。

您在正确的轨道上更喜欢在视图模型级别而不是视图本身(例如TextBox )执行此操作。 将所有非 UI 逻辑放在视图模型中的次数越多越好。

请注意,这实际上意味着您最好拥有一个“主”视图模型,它保存Person对象和当前选定项目的列表,而不是让您的窗口实现INotifyPropertyChanged

另外,它的价值,我发现它工作得更好(对我来说,反正)来实现一个基类,视图模型对象继承,它有一个辅助方法来更新支持字段,提高PropertyChanged是必要的,并且提供了一个可选的回调允许响应属性更改,而不必实际订阅事件(至少在您总是想响应的情况下……在这个特定示例中,这可能无济于事,因为您只想在Person对象处于当前选择的一个)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM