Wpf 如果其他类对象的属性更改,Gui不更新

Wpf 如果其他类对象的属性更改,Gui不更新,wpf,xaml,data-binding,Wpf,Xaml,Data Binding,我想将自定义类(FooClass)的一些属性(FooClass.FooString)绑定到我的主窗口。下面(工作已知行为)是将某些数据绑定到gui的默认工作解决方案 我想做的是在第二个代码块中(不工作,但需要的行为)。将另一个类对象的一些属性公开到gui并更新它。 **问题**:TestString未得到更新(在gui上,代码隐藏起作用)。属性更改事件也是null`(未订阅?!) 这是绑定数据的错误方法吗 如果我将完整的Foo类对象绑定到gui,并将路径(属于文本块)设置为Foo.FooStri

我想将自定义类(
FooClass
)的一些属性(
FooClass.FooString
)绑定到我的
主窗口。下面(工作已知行为)是将某些数据绑定到gui的默认工作解决方案

我想做的是在第二个代码块中(不工作,但需要的行为)。将另一个
对象
的一些
属性
公开到gui并更新它。 **问题**:
TestString
未得到更新(在gui上,代码隐藏起作用)。
属性更改
事件
也是
null`(未订阅?!)

这是绑定数据的错误方法吗

如果我将完整的
Foo类
对象
绑定到gui,并将
路径
(属于
文本块
)设置为
Foo.FooString
,gui和
字符串
将更新。但我不想这样做

这就是解决问题的方法吗


工作已知行为
我可能还没有完全理解您想要什么,但这里有一个数据绑定的工作示例,它与您的示例有些接近

两个主要变化是:

  • 将datacontext设置为VM,而不是代码隐藏
  • 实际上,为OnPropertyChanged提供正确触发刷新所需的参数,即属性的名称
  • 结果:

    main window.xaml

    <Window x:Class="ListViewColor.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>
            <TextBlock Text="{Binding Foo.FooString}" VerticalAlignment="Center" HorizontalAlignment="Center" Background="Aqua"/>
        </Grid>
    </Window>
    
    FooClass.cs


    我希望这有帮助

    是的,您是正确的,您需要通过“工作已知行为”部分进行绑定。您需要订阅INotifyPropertyChanged.PropertyChanged事件,然后从MainWindow类内部引发相同的事件。与其将
    this
    aka
    MainWindow
    类绑定到
    DataContext
    ,不如将
    Foo
    绑定到
    DataContext
    ?然后可以将
    TextBlock
    Text
    设置为绑定到
    FooString
    。这让生活变得更轻松。@Bijington看一看解决方案1。你是那个意思吗?@kurakura88在我的应用程序中,我有不止一个不同的类对象,而不仅仅是一个。请注意,在主窗口中实现INotifyPropertyChanged是毫无意义的。没有应该触发更改通知的属性。@是的,这就是我的意思。不过,我不推荐这种方法,因为它与推荐的做法背道而驰。你真的应该坚持你原来的方法,我只是指出这在技术上是可能的。谢谢你的回复。1.实际上,它正在使用
    DataContext=this
    。然后你必须定义你的路径,比如
    path=Foo.FooString
    。2.看看@Dominicjons嘿,你两次都是对的!我学到了一些东西。但是我不明白这个问题,因为即使有这些变化,它也能完美地工作!除了上面编辑的代码,您还需要什么吗?
    <Window x:Class="WpfApp1.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"
            xmlns:local="clr-namespace:WpfApp1"
            mc:Ignorable="d"
            d:DataContext="{d:DesignInstance local:MainWindow}"
            Title="MainWindow" Height="450" Width="800">
        <Grid>
            <TextBlock Text="{Binding Path=Foo.FooString}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
        </Grid>
    </Window>
    
    public partial class MainWindow : Window
    {
        public string TestString => _Foo.FooString;
    
    
        private readonly FooClass _Foo;
    
        public MainWindow()
        {
            _Foo = new FooClass();
            DataContext = this;
            InitializeComponent();
    
            Loaded += _OnLoaded;
        }
    
        private async void _OnLoaded(object sender, RoutedEventArgs e)
        {
            await Task.Delay(1000);
            _Foo.ChangeTheProperty();
        }
    }
    
    public class FooClass : INotifyPropertyChanged
    {
        public string FooString
        {
            get => _FooString;
            set
            {
                if (_FooString == value) return;
                _FooString = value;
                OnPropertyChanged();
            }
        }
        private string _FooString = "empty";
    
        public void ChangeTheProperty()
        {
            FooString = "Loaded";
        }
    
        // ##############################################################################################################################
        // PropertyChanged
        // ##############################################################################################################################
    
        #region PropertyChanged
    
        /// <summary>
        /// The PropertyChanged Eventhandler
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;
    
        /// <summary>
        /// Raise/invoke the propertyChanged event!
        /// </summary>
        /// <param name="propertyName"></param>        
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    
        #endregion
    }
    
    <Window x:Class="WpfApp1.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"
            xmlns:local="clr-namespace:WpfApp1"
            mc:Ignorable="d"
            d:DataContext="{d:DesignInstance local:MainWindow}"
            Title="MainWindow" Height="450" Width="800">
        <Grid>
            <TextBlock Text="{Binding Path=TestString}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
        </Grid>
    </Window>
    
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public FooClass Foo { get; } = new FooClass();
    
        public MainWindow()
        {
            Foo.PropertyChanged += (sender, args) => OnPropertyChanged(args.PropertyName);
            DataContext = this;
            InitializeComponent();
    
            Loaded += _OnLoaded;
        }
    
        private async void _OnLoaded(object sender, RoutedEventArgs e)
        {
            await Task.Delay(1000);
            Foo.ChangeTheProperty();
        }
    
    
        // ##############################################################################################################################
        // PropertyChanged
        // ##############################################################################################################################
    
        #region PropertyChanged
    
        /// <summary>
        /// The PropertyChanged Eventhandler
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;
    
        /// <summary>
        /// Raise/invoke the propertyChanged event!
        /// </summary>
        /// <param name="propertyName"></param>
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    
        #endregion
    
    }
    
    <Window x:Class="ListViewColor.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>
            <TextBlock Text="{Binding Foo.FooString}" VerticalAlignment="Center" HorizontalAlignment="Center" Background="Aqua"/>
        </Grid>
    </Window>
    
    namespace ListViewColor
    {
        public partial class MainWindow : Window
        {
            public FooClass Foo { get; } = new FooClass();
    
            public MainWindow()
            {
                DataContext = this;
                InitializeComponent();
                Loaded += _OnLoaded;
            }
    
            private async void _OnLoaded(object sender, RoutedEventArgs e)
            {
                await Task.Delay(1000);
                Foo.ChangeTheProperty();
            }
        }
    }
    
    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    
    public class FooClass : INotifyPropertyChanged
    {
        private string _FooString = "Empty";
        public string FooString
        {
            get
            {
                return _FooString;
            }
            set
            {
                if (_FooString == value) return;
                _FooString = value;
                OnPropertyChanged();
            }
        }
    
        public void ChangeTheProperty()
        {
            FooString = "Loaded";
        }
    
        #region PropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion
    }