WPF从MVVM视图模型设置DataTemplate UI元素的可见性

WPF从MVVM视图模型设置DataTemplate UI元素的可见性,wpf,mvvm,wpf-controls,visibility,datatemplate,Wpf,Mvvm,Wpf Controls,Visibility,Datatemplate,我有一个设置为DataTemplate的控件: <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <BooleanToVisibilityConverter x:Key="BoolToVis" /> <

我有一个设置为DataTemplate的控件:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<BooleanToVisibilityConverter x:Key="BoolToVis" />
<DataTemplate x:Key="KEYBOARD_EN">
     <StackPanel>
               <Button Visibility="{Binding Path=RegisterButtonVisible}"  Style="{StaticResource RegisterKeyboardButtonStyle}">Register</Button>

    </StackPanel>        
</DataTemplate>
在我的ViewModel中,我执行以下操作:

    public Visibility RegisterButtonVisible // get, set, raisepropchange, etc
带有按钮的My DataTemplate包装在userControl中:

<UserControl x:Class="Bleh.Assets.MainKeyboard"
         x:Name="TheControl"
         Unloaded="UserControl_Unloaded">

<Viewbox>
    <Grid>
        <ContentControl Name="ctrlContent" Button.Click="Grid_Click" />
    </Grid>
</Viewbox>
这是我的依赖属性。它显示在intelliesense中,因此CLR已正确注册它,但它不拾取属性分配(忽略折叠)

这让我觉得它非常接近,但我记得有人告诉我我不能这样做,因此EventTriggers(这显然是datatemplates和MVVM的常见问题)

因此,一种选择是在交互名称空间中使用一些东西,就像我使用事件触发器一样(我只需要以某种方式在这个按钮上触发一个“可见性”触发器,至少我认为是这样)

在MVVM中这样做的正确方法是什么?

修复代码 为了使现有代码正常工作,您需要告诉WPF应该从哪个对象读取
RegisterButtonVisible
。如果是用户控件,请为
UserControl
指定一个名称,然后通过
ElementName
引用该元素,如下所示:


在按钮绑定中:

寄存器
当然,如果由于按钮和usercontrol位于不同的文件中而无法执行此操作,则仍然可以使用祖先绑定:

<Button Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type assets:MainKeyboard}},
                             Path=RegisterButtonVisible}"
        Style="{StaticResource RegisterKeyboardButtonStyle}">Register</Button>    

当然,这是假设您的DataContext设置正确,并且指向您的ViewModel。

不要被正确/错误所困扰……这实际上是因为更容易继续维护。依我拙见我会像你所展示的那样在虚拟机上进行可见性,并从其他属性触发它,并在代码中添加一个好的注释;我只是想用MVVM的方式做事;先看一看。但我绝对同意你的看法,我不能做后者,因为我的数据上下文是不可定义的;它是IoC,需要模拟对象,因此没有构造函数允许我设置datacontext。所有视图模型都是通过数据模板定义的。但是我现在正在尝试前者。@nocarrier您也可以在codebehind中设置DataContext。因此,在您的窗口(或用户控件等)中,您可以执行传递给构造函数的
this.DataContext=myviewmodel
。然后,您可以在WPF代码中随意使用数据上下文。两个问题@MackieChan-为了路由此属性,我将在“TheControl”的代码中添加什么?Simpley指定ElementName=控件似乎没有任何效果。其次,我是否可以在承载此用户控件的控件中指定一种样式来设置可见性,如以下回答所示:我使用datatemplate添加了一些编辑,以及它在视图中的使用方式(使用UC)。@nocarrier(1)我添加了一个不使用名称,而是使用祖先绑定的示例。(2)是的,您可以定义也使用祖先绑定的动态样式。
<UserControl x:Class="Bleh.Assets.MainKeyboard"
         x:Name="TheControl"
         Unloaded="UserControl_Unloaded">

<Viewbox>
    <Grid>
        <ContentControl Name="ctrlContent" Button.Click="Grid_Click" />
    </Grid>
</Viewbox>
  <assets:MainKeyboard 
      RegisterButtonVisible="Collapsed"
                                 Loaded="MainKeyboard_Loaded">
                <b:Interaction.Triggers>
                    <b:EventTrigger EventName="Register">
                        <b:InvokeCommandAction Command="{Binding ConfirmEmailAddressCommand}"/>
                    </b:EventTrigger>
                    <b:EventTrigger EventName="Enter">
                        <b:InvokeCommandAction Command="{Binding EnterKeyCommand}"/>
                    </b:EventTrigger>
                </b:Interaction.Triggers>
            </assets:MainKeyboard>
 RegisterButtonVisible="Collapsed" 
<Button Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type assets:MainKeyboard}},
                             Path=RegisterButtonVisible}"
        Style="{StaticResource RegisterKeyboardButtonStyle}">Register</Button>