c# - WPF 依赖属性已更改但未在绑定中生效
问题描述
我遇到了我之前在这里发布的一个问题。我仍在为这个问题苦苦挣扎,所以我试图用更小的代码设置来分解它。
问题:
我有一个依赖属性绑定到视图模型,它不会用更改的值@construction time更新视图模型。
绑定似乎是正确的,因为在应用程序启动后更改 XAML 中的值(依赖于 xaml 热重载)确实会通过更改更新视图模型。
我可以通过以下设置重现该问题:
主窗口:
<Grid>
<local:UserControl1
SomeText="My changed text"
DataContext="{Binding UserControlViewModel}"/>
</Grid>
主视图模型:
public class MainViewModel
{
public UserControlViewModel UserControlViewModel { get; set; }
public MainViewModel()
{
UserControlViewModel = new UserControlViewModel();
}
}
用户控制:
<UserControl.Resources>
<Style TargetType="local:UserControl1">
<Setter Property="SomeText" Value="{Binding MyText, Mode=OneWayToSource}"></Setter>
</Style>
</UserControl.Resources>
<Grid>
<TextBlock Text="{Binding MyText}"></TextBlock>
</Grid>
后面的 UserControl 代码:
public static readonly DependencyProperty SomeTextProperty = DependencyProperty.Register(
nameof(SomeText),
typeof(string),
typeof(UserControl1),
new PropertyMetadata("default text", PropertyChangedCallback));
public string SomeText { get; set; }
private static void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// first and only update: 'default text' => 'My changed text'
}
public UserControl1()
{
InitializeComponent();
}
UserControl 视图模型:
public class UserControlViewModel
{
// Setter is called with 'default text'
// AFTER the property changed callback is triggered with updated text
public string MyText { get; set; }
}
当我运行应用程序时,会显示文本“默认文本”,而我预计会显示“我更改的文本”。
然后当我在 XAML 中更改 SomeText 属性时,我再次看到更改后的回调触发,因此我看到视图模型设置器得到更新。这次更改了值。因此,绑定似乎工作正常,但在启动期间它无法使用(已知的)更改值更新视图模型。
任何人都可以解释是什么导致了这个问题?有没有办法解决这个问题?
更新
我刚刚发现,当我更改 XAML(使用热重载)时,更新顺序是:
- 首先设置视图模型的设置器
- 然后OnPropertyChanged 回调触发。
- 结果是更改后的值显示在 UI 上
这与施工时发生的情况相反。然后顺序是:
- OnPropertyChanged 回调触发
- 视图模型的设置器已设置。
- 结果是默认值显示在 UI 上(如原始问题中所述)
这真的很奇怪。因为当 Property Changed 回调触发时(在启动期间),我可以将其DependencyObject
转换回我的 UserControl 并检查其数据上下文。数据上下文当时为空。
我之前的热重载实验证明最终绑定工作完美。
- 因此,第 1 步是将文本“我更改的文本”设置为依赖属性。
- 第 2 步是将视图模型作为数据上下文连接到 MyUserControl
- 第 3 步是评估绑定,在这种情况下,绑定 (onewaytosource) 获得初始同步,但使用旧值。
对我来说,这看起来像是 WPF 中的一个错误。
解决方案
您为您的用例使用了错误的绑定模式。
当您指定 OneWayToSource 时,您只允许数据从您的文本框流向 ViewModel 中的属性,因为源是 MyText 属性。
尝试删除 Mode=OneWayToSource,或者如果您希望从 View 和 ViewModel 更新文本,请使用 TwoWay。(IIRC TwoWay 是 TextBox 控件的默认模式)。
另外,您的 ViewModel 是否实现了 INotifyPropertyChanged 接口来支持绑定?
解释不同模式的小总结在这个SO 答案中
推荐阅读
- amazon-product-api - 错误 ActiveContractNotFound 是什么意思 - Amazon Gift Card On Demand (AGCOD)
- ruby-on-rails - 如何在表单中动态添加字段
- amazon-web-services - 如何为 AWS Step Functions 中的活动添加动态 TimeoutSeconds?
- batch-file - 为什么不设置时间,然后重新设置它对我有利?
- python - 保存对象后,字段值的总和未返回正确的值
- javascript - 通过对象过滤 MultiCheckbox
- oracle - 在 Oracle 中,IN 运算符后面是否有数据类型?
- javascript - 当父级悬停时如何更改组件的样式?
- c# - 如何从 C# 客户端(控制台应用程序)向 WebAPI 项目请求 POST
- java - 如何通过 Android Java 中的 LifeCycle 事件和事件总线支持从多个活动中固有?