首页 > 解决方案 > 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(使用热重载)时,更新顺序是:

这与施工时发生的情况相反。然后顺序是:

这真的很奇怪。因为当 Property Changed 回调触发时(在启动期间),我可以将其DependencyObject转换回我的 UserControl 并检查其数据上下文。数据上下文当时为空。

我之前的热重载实验证明最终绑定工作完美。

对我来说,这看起来像是 WPF 中的一个错误。

标签: c#wpfmvvmdependency-properties

解决方案


您为您的用例使用了错误的绑定模式。

当您指定 OneWayToSource 时,您只允许数据从您的文本框流向 ViewModel 中的属性,因为源是 MyText 属性。

尝试删除 Mode=OneWayToSource,或者如果您希望从 View 和 ViewModel 更新文本,请使用 TwoWay。(IIRC TwoWay 是 TextBox 控件的默认模式)。

另外,您的 ViewModel 是否实现了 INotifyPropertyChanged 接口来支持绑定?

解释不同模式的小总结在这个SO 答案中


推荐阅读