传递给 UserControl 的继承 ViewModel 被视为子 ViewModel

Inherited ViewModel passed to UserControl is treated as child ViewModel

我有一个视图 MainWindow.xaml,其中包含两个在 Button.xaml 中定义的按钮。该按钮绑定到 属性 IsVisible 定义按钮是否可见。

MainWindow.xaml:

<local:Button DataContext="{Binding ButtonViewModel1}" />
<local:Button DataContext="{Binding ButtonViewModel2}" />

Button.xaml:

<StackPanel>
    <Button Name="MyButton" Visibility="{Binding IsVisible}">
        <TextBlock>My Button</TextBlock>
    </Button>
</StackPanel>

对于按钮,我有两个 ViewModel:ButtonViewModelButtonViewModelChild

ButtonViewModelChild 继承自 ButtonViewModel。两者都提供 IsVisible 属性:

ButtonViewModel:

public Visibility IsVisible
{
    get
    {
        return Visibility.Hidden;
    }
}

ButtonViewModelChild:

public new Visibility IsVisible
{
    get
    {
        return Visibility.Visible;
    }
}

MainWindow.xaml 的 ViewModel 包含 属性 ButtonViewModel1ButtonViewModel2。这些属性如下所示:

public ButtonViewModel ButtonViewModel1
{
    get
    {
        return new ButtonViewModelChild();
    }
}

public ButtonViewModelChildButtonViewModel2
{
    get
    {
        return new ButtonViewModelChild();
    }
}

如果 ButtonViewModel 用作按钮的 DataContext,按钮应该是不可见的;如果使用 ButtonViewModelChild,按钮应该是可见的。

我假设使用 ButtonViewModel1 作为 DataContext 的按钮获得 ButtonViewModel,另一个按钮获得 ButtonViewModelChild。所以第一个按钮将不可见,而第二个按钮会。虽然这两个按钮都是可见的。 WPF在这里做什么?显然,它两次都使用实例的继承视图。有没有办法告诉 WPF 使用 属性 的 return 类型而不是创建的实例类型?

我知道方法隐藏不是最佳实践。我可能会更改设计,但我很好奇为什么结果不如预期。

绑定路径中的 属性 通过反射解析,因此它找到子 class 属性,而不管 ButtonViewModel1 属性 类型。

public ButtonViewModel ButtonViewModel1
{
    get { return new ButtonViewModelChild(); } // subclass instance
}

为避免这种情况,您必须 return 来自 getter:

ButtonViewModel 实例
public ButtonViewModel ButtonViewModel1
{
    get { return new ButtonViewModel(); }
}

您也可以将 属性 声明为 object,绑定仍然有效:

public object ButtonViewModel1
{
    get { return new ButtonViewModelChild(); }
}

除此之外,您通常不应让 UserControl 操作特定的视图模型(从而使其依赖于 viel 模型 class)。相反,您应该在 UserControl class 中声明一个 IsButtonVisible 依赖项 属性,然后像这样绑定它:

<StackPanel>
    <Button Visibility="{Binding IsButtonVisible,
                         RelativeSource={RelativeSource AncestorType=UserControl}}">
        <TextBlock>My Button</TextBlock>
    </Button>
</StackPanel>

用法为:

<local:Button IsButtonVisible="{Binding ButtonViewModel1.IsVisible}" />

我认为问题是你的 getter 中的类型错误,它们都是 return ButtonViewModelChild viewmodel,当你从 ButtonViewModel1 而不是 ButtonViewModelChild 的 return ButtonViewModel 时应该隐藏