所以我可能不太了解绑定,于是我想到了这个测试项目,可以在其中以简单的方式展示我的问题。我需要在哪里更改项目以使绑定更新视图?
这是我的项目,以备您下载时使用: 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属性,并且将更新视图
。那么如何更改代码以使绑定起作用?
答案 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传播。这是一种坏做法,导致的问题多于解决方案。
在运动中可以接受设置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();
}
}