当静态 ObservableCollection 的元素的 属性 被修改时更新 UI

Updating UI when a property of an element of a static ObservableCollection is modified

我的问题分为两部分:

  1. 当在 xaml 中使用 Content="{Binding SelectedPerson.Age}" 而不是时,标签内容不会更新 SelectedPersonAge.Content = SelectedPerson.Age; 参考 。我已经设置 datacontextSelectedPerson 是 属性.
  2. 即使在更改组合框项目时更新(使用隐藏代码),当对所选项目标签字段的一个属性进行修改时未更新,我尝试实施 INotifyPropertyChanged 但它在 .add() .delete() .clear() 涉及但不涉及 Peoplelist[0].Age = 5;.

我做错了什么?不使用复杂的mvvm外部框架,是否可以通过简单的代码实现?

Mainwindow.xaml.cs

using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace WpfTest
{
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public ObservableCollection<People> Peoplelist { get; set; } = new ObservableCollection<People>();
        public event PropertyChangedEventHandler PropertyChanged;
        private People _SelectedPerson;

        public People SelectedPerson
        {
            get { return _SelectedPerson; }
            set
            {
                if (value != _SelectedPerson)
                {
                    _SelectedPerson= value;
                    NotifyPropertyChanged("SelectedPerson");
                }
            }
        }

        private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public MainWindow()
        {
            People.Populate(Peoplelist);

            InitializeComponent();
            DataContext = this;
        }

            private void Button_Click(object sender, RoutedEventArgs e)
        {
            //Modify Jon's Age property while it's selected: not automatically updating in ui
            Peoplelist[0].Age = 5;
        }

        private void combo1_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
        {
            SelectedPersonAge.Content = SelectedPerson.Age;  //not working when put in xaml
        }
    }


    public class People : INotifyPropertyChanged
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        private int _Age;
        public int Age
        {
            get { return _Age; }
            set
            {
                _Age = value;
                RaisePropertyChanged("Age");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }


        public People() { }

        public People(String _FirstName, String _FamilyName)
        {
            FirstName = _FirstName;
            LastName = _FamilyName;
            Age = 0;
        }

        public static void Populate(ObservableCollection<People> lst)
        {
            lst.Add(new People
            {
                FirstName = "Jon",
                LastName = "Jonathan",
            });
            lst.Add(new People
            {
                FirstName = "Mark",
                LastName = "Markthan",
            });
            lst.Add(new People
            {
                FirstName = "Spence",
                LastName = "Spencer",
            });
        }
    }
}

MainWindow.xaml

<Window x:Class="WpfTest.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"
           mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <StackPanel>
            <ComboBox  Name="combo1" VerticalAlignment="Center" HorizontalAlignment="Center" MinWidth="200" SelectedValuePath="Age" SelectionChanged="combo1_SelectionChanged" ItemsSource="{Binding Path=Peoplelist}" SelectedItem="{Binding SelectedPerson}">
                <ComboBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <TextBlock Text="{Binding FirstName}"/>
                            <TextBlock Text="--"/>
                            <TextBlock Text="{Binding LastName}"/>
                        </StackPanel>
                    </DataTemplate>
                </ComboBox.ItemTemplate>
            </ComboBox>
            <Label Name="SelectedPersonAge" Width="200" Height="35" HorizontalAlignment="center" VerticalAlignment="center" Content="{Binding SelectedPerson.Age}"/>
            <Button Height="35"  Click="Button_Click">
                Test
            </Button>
        </StackPanel>
    </Grid>
</Window>

正如@PeterDuniho 在他的 中指出的那样,我使用 DataContext="{Binding ElementName=MyWindow}.

更正了控件组合框和标签的 DataContext

SelectedPersonAge.Content = combo1.SelectedValue; 不再需要,因为它已在 xaml.

中实现

Mainwindow.xaml.cs

using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace WpfTest
{
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public ObservableCollection<People> Peoplelist { get; set; } = new ObservableCollection<People>();
        public event PropertyChangedEventHandler PropertyChanged;
        private People _SelectedPerson;

        public People SelectedPerson
        {
            get { return _SelectedPerson; }
            set
            {
                if (value != _SelectedPerson)
                {
                    _SelectedPerson= value;
                    NotifyPropertyChanged("SelectedPerson");
                }
            }
        }

        private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public MainWindow()
        {
            People.Populate(Peoplelist);

            InitializeComponent();
        }

            private void Button_Click(object sender, RoutedEventArgs e)
        {
            //Modify Jon's Age property while it's selected: not automatically updating in ui
            Peoplelist[0].Age = 5;
        }

        private void combo1_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
        {
        }
    }


    public class People : INotifyPropertyChanged
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        private int _Age;
        public int Age
        {
            get { return _Age; }
            set
            {
                _Age = value;
                RaisePropertyChanged("Age");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }


        public People() { }

        public People(String _FirstName, String _FamilyName)
        {
            FirstName = _FirstName;
            LastName = _FamilyName;
            Age = 0;
        }

        public static void Populate(ObservableCollection<People> lst)
        {
            lst.Add(new People
            {
                FirstName = "Jon",
                LastName = "Jonathan",
            });
            lst.Add(new People
            {
                FirstName = "Mark",
                LastName = "Markthan",
            });
            lst.Add(new People
            {
                FirstName = "Spence",
                LastName = "Spencer",
            });
        }
    }
}

MainWindow.xaml

<Window x:Class="WpfTest.MainWindow" x:Name="MyWindow"
        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"
           mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <StackPanel>
            <ComboBox  Name="combo1" VerticalAlignment="Center" HorizontalAlignment="Center" MinWidth="200" SelectedValuePath="Age" SelectionChanged="combo1_SelectionChanged" ItemsSource="{Binding Path=Peoplelist}" SelectedItem="{Binding SelectedPerson}" DataContext="{Binding ElementName=MyWindow}">
                <ComboBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <TextBlock Text="{Binding FirstName}"/>
                            <TextBlock Text="--"/>
                            <TextBlock Text="{Binding LastName}"/>
                        </StackPanel>
                    </DataTemplate>
                </ComboBox.ItemTemplate>
            </ComboBox>
            <Label Name="SelectedPersonAge" Width="200" Height="35" HorizontalAlignment="center" VerticalAlignment="center" Content="{Binding SelectedPerson.Age}" DataContext="{Binding ElementName=MyWindow}"/>
            <Button Height="35"  Click="Button_Click">
                Test
            </Button>
        </StackPanel>
    </Grid>
</Window>