为什么绑定对TestClass不起作用,但是设置相同的属性却起作用?

时间:2019-10-15 12:16:27

标签: c# wpf data-binding

所以我可能不太了解绑定,于是我想到了这个测试项目,可以在其中以简单的方式展示我的问题。我需要在哪里更改项目以使绑定更新视图?

这是我的项目,以备您下载时使用: https://1drv.ms/u/s!AqdZJMIRBGu7z1V8K1jXN9BQWFQ-?e=oxdlhL

这是一些代码:

TestClass.cs:

 public class TestClass
 {
     public string Text { get; set; } = "Default";
 } 

TestClassView.xaml:

<UserControl x:Class="Test.TestClassView" ...>
   <Grid>
      <TextBlock Text="{Binding TestClass.Text}" />
   </Grid>
</UserControl>

TestClassView.xaml.cs:

public partial class TestClassView : UserControl
{
    public TestClass TestClass 
    {
        get { return (TestClass)GetValue(TestClassProperty); }
        set { SetValue(TestClassProperty, value); }
    }
    public static readonly DependencyProperty TestClassProperty = DependencyProperty.Register("TestClass", typeof(TestClass), typeof(TestClassView), new PropertyMetadata(new TestClass() { Text = "Default"}));

    public TestClassView()
    {
        InitializeComponent();

        DataContext = this;
    }

MainWindow.xaml:

<Window x:Class="Test.MainWindow" ...>
   <Grid>
      <WrapPanel Margin="10">
         <Button Content="Test" Click="Button_Click" />
         <local:TestClassView x:Name="TestClassView" TestClass="{Binding TestClass}" />
      </WrapPanel>
   </Grid>
</Window>

MainWindow.xaml.cs:

public partial class MainWindow : Window, INotifyPropertyChanged
{
    private TestClass testClass = new TestClass() { Text = "DefaultProperty" };
    public TestClass TestClass { get { return testClass; } set{ testClass = value; OnPropertyChanged(); } }
    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;
    }
    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged([CallerMemberName]string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private async void Button_Click(object sender, RoutedEventArgs e)
    {
        TestClass = new TestClass() { Text = "Test1" };
        MessageBox.Show("Test 1 Done");
        await Task.Delay(1000);
        TestClassView.TestClass = new TestClass() { Text = "Test2" };
        MessageBox.Show("Test 2 Done");
    }
}

因此,当我单击按钮时,首先设置MainWindow的TestClass实例,该实例绑定到TestClassView的DependencyProperty调用TestClass。我也叫PropertyChanged,但是TestClassView属性不会更新。

一秒钟之后,在click事件处理程序的第二部分,实际上设置了TestClassView TestClass属性,并且将更新视图

那么如何更改代码以使绑定起作用?

2 个答案:

答案 0 :(得分:1)

我会说TestClassView不需要TestClass属性。它的用法与DataContext属性相同。

public partial class TestClassView : UserControl
{
    public TestClassView()
    {
        InitializeComponent();
    }
}

<UserControl x:Class="Test.TestClassView" ...>
   <Grid>
      <TextBlock Text="{Binding Text}" />
   </Grid>
</UserControl>

和窗口:

<Window x:Class="Test.MainWindow" ...>
   <Grid>
      <WrapPanel Margin="10">
         <Button Content="Test" Click="Button_Click" />
         <local:TestClassView x:Name="TestClassView" DataContext="{Binding TestClass}" />
      </WrapPanel>
   </Grid>
</Window>

public partial class MainWindow : Window, INotifyPropertyChanged
{
    private TestClass testClass = new TestClass() { Text = "DefaultProperty" };
    public TestClass TestClass { get { return testClass; } set { testClass = value; OnPropertyChanged(); } }

    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged([CallerMemberName]string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private async void Button_Click(object sender, RoutedEventArgs e)
    {
        TestClass = new TestClass() { Text = "Test1" };
        MessageBox.Show("Test 1 Done");
        await Task.Delay(1000);
        TestClass = new TestClass() { Text = "Test2" };
        MessageBox.Show("Test 2 Done");
    }
}

在原始示例中,绑定不起作用,因为TestClassView控件通过在构造函数中设置DataContext = this;来中断DataContext传播。这是一种做法,导致的问题多于解决方案。

在Windows中

在运动中可以接受设置DataContext = this; ,因为它可以快速设置,但是通常视图将单独的ViewModel类用于DataContext。

答案 1 :(得分:1)

在绑定中,您绑定到TestClass的属性:

<TextBlock Text="{Binding TestClass.Text}" />

,以便该属性需要引发PropertyChanged。从其他物体上抬起它是没有用的。

private string text = "Default";
public string Text 
{ 
    get => return this.text;
    set 
    { 
        this.text = value;
        this.NotifyPropertyChanged();
    } 
 }