【问题标题】:Updating UI when a property of an element of a static ObservableCollection is modified修改静态 ObservableCollection 元素的属性时更新 UI
【发布时间】:2020-07-22 17:37:03
【问题描述】:

我的问题分为两部分:

  1. 在 xaml 中使用 Content="{Binding SelectedPerson.Age}" 而不是 SelectedPersonAge.Content = SelectedPerson.Age; 指的是Why binding using ItemsSource is working in code but not in xaml?。我已经设置了datacontext 和SelectedPerson 是一个属性。
  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>

【问题讨论】:

  • 暂时忽略使用this 作为窗口数据上下文的非常不明智的选择,您甚至没有在Label 中使用它,而是明确地将数据上下文设置为字符串"combo1"。即使您使用了{x:Reference...},上下文仍然是错误的,因为它是具有您想要的属性的窗口,而不是ComboBox。目前尚不清楚您为什么要在此处设置 DataContext 属性...我建议将其删除。如果您这样做,它可能会“正常”工作(同样,不包括将视图模型内容放入窗口的更广泛的问题)。
  • @PeterDuniho 哦,这太傻了,抱歉我对这一切都不熟悉。当我在标签中设置DataContext="{Binding} 时,确实一切正常。但是,如果我从代码comobobox 中删除DataContext = this; 变为空,我应该如何解决这个问题?我把所有东西都放在主窗口中只是为了测试。
  • @PeterDuniho 在组合框和标签 DataContext="{Binding ElementName=MyWindow} 中设置的 DataContext 下一切正常。谢谢。

标签: c# wpf xaml binding observablecollection


【解决方案1】:

正如@PeterDuniho 在他的comment 中指出的那样,我使用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>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-05-18
    • 1970-01-01
    • 2015-04-06
    • 1970-01-01
    • 1970-01-01
    • 2017-06-25
    • 2014-01-01
    • 1970-01-01
    相关资源
    最近更新 更多