如果其他类对象的属性发生了变化,Gui不会更新

时间:2018-05-09 06:52:19

标签: wpf xaml data-binding

我想将自定义类(FooClass.FooString)的某些属性(FooClass)绑定到我的MainWindow。现在,如果将一些数据绑定到gui,则下面(工作已知行为)是默认的工作解决方案。

我想要做的是在第二个代码块中(不工作,但需要的行为)。公开另一个properties对象class对象to the gui and update it. **Problem**: The TestString is not getting updated (on the gui, code behind works). The PropertyChanged 事件is also null`(未订阅?!)。

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

如果我将完整的FooClass object绑定到gui并将PathTextBlock)设置为Foo.FooString,则gui和{{1} }已更新。但我不想这样做。

这是如何解决的?

工作已知行为

string

MainWindow.xaml

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

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=Foo.FooString}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
    </Grid>
</Window>

MainWindow.xaml

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
}

解决方案1 ​​

订阅<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> Foo.PropertyChanged并将其发送至event

MainWindow.PropertyChanged

1 个答案:

答案 0 :(得分:0)

我可能还没有完全理解你想要的东西,但这里有一个数据绑定的工作示例,这与你的例子有点接近。

两个主要变化是:

  1. 将datacontext设置为VM,而不是
  2. 背后的代码
  3. 实际上给OnPropertyChanged提供正确触发刷新所需的参数,即属性的名称。
  4. <强>结果: enter image description here

    <强> MainWindow.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>
    

    <强> MainWindow.xaml.cs

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

    <强> FooClass.cs

    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
    }
    

    我希望有所帮助!