WPF控件属性在“代码后台”设置后,绑定被忽略。

4

我在WPF方面非常新手。我尝试在代码中为控件属性设置默认值,并希望在数据上下文(VM)可用时通过数据绑定覆盖该属性。但在这种情况下,数据绑定不起作用。

示例:

代码:

public partial class MyViewControl : UserControl
{
    public MyViewControl()
    {
        InitializeComponent();
        // it works if I remove this line
        panelControl.Visibility = Visibility.Hidden;
    }
}

XAML用户控件:

<DockPanel Name="panelControl" Visibility="{Binding
MyViewModelProperty_IsVisible_ConvertedToVisibility}">

XAML主窗口:

<my:MyViewControl DataContext="{Binding  ElementName=lbListBox,
Path=SelectedItem}"/>

实际上,FallbackValue参数可以解决这个问题,但我想知道技术原因,为什么控件属性在被代码设置后不能绑定?


1
“cannot be bound after it was set by code” - 实际上不是在之后,绑定发生在 InitializeComponent 中的某个位置(在你覆盖它之前),在你的代码中,你只是在设置绑定之后又覆盖了它(意味着没有绑定了)。尝试在那行代码之后再次设置绑定。问题是为什么要这样做? - Sinatr
最初我尝试设置默认值。但是我已经找到了适用于此目的的FallbackValue参数。所以问题就出现了,要理解框架如何工作... - tcpw
2个回答

4

Xaml在InitializeComponent()期间进行处理,因此这就是正在发生的事情:

InitializeComponent(); // binding is set
panelControl.Visibility = Visibility.Hidden; // binding is removed (value is set)

您可以恢复绑定。
InitializeComponent();
panelControl.Visibility = Visibility.Hidden;
BindingOperations.SetBinding(panelControl, Control.VisibilityProperty,
    new Binding()
{
    Path = new PropertyPath(nameof(ViewModel.MyViewModelProperty_IsVisible_ConvertedToVisibility)),
    Source = viewModelInstance, // this.DataContext ?
});

之后它将起作用。但是不太清楚为什么要首先覆盖绑定。


如果在InitializeComponent之后更改属性值,那么属性绑定将被移除。明白了。 - tcpw
FallbackValue在绑定失败时(例如当DataContext == null时)被使用。它确实经常用作设计时默认值,但它也在运行时有用途(例如当转换器显式返回UnsetValue时)。 - Sinatr

2

在代码中改变绑定属性值时,防止绑定被清除的简单方法是使用 TwoWay 绑定模式:

<DockPanel Name="panelControl"
           Visibility="{Binding MyViewModelProperty_IsVisible_ConvertedToVisibility,
                        Mode=TwoWay}">

我当然是吃了亏才明白这个道理,哈哈。
实际上,如果您有修改控件属性的原因(而不是修改绑定属性),使用 TwoWay 模式确实是有意义的 - 然后您希望绑定属性也反映出更改。
顺便说一下,与其绑定到 Visibility 类型的属性,最好绑定到布尔值并使用转换器(如 BooleanToVisibilityConverter),因为它可以更好地将 ViewModelView 解耦:
<Window.Resources>
    <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Window.Resources>

...

<DockPanel Name="panelControl"
           Visibility="{Binding MyViewModelProperty_IsVisible,
                        Converter={StaticResource BooleanToVisibilityConverter},
                        Mode=TwoWay}">

是的,我知道这是一个旧问题,并且已经有了一个被接受的答案,但我没有找到其他直接提供此解决方案的答案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接