将 IsEnabled 绑定到父 ViewModel 而不是 UserControl ViewModel

Posted

技术标签:

【中文标题】将 IsEnabled 绑定到父 ViewModel 而不是 UserControl ViewModel【英文标题】:Binding IsEnabled to the parent ViewModel instead of the UserControl ViewModel 【发布时间】:2011-07-19 12:26:47 【问题描述】:

我在 SilverLight 中开发了一个包含多个子控件的用户控件。 TextboxesComboBoxes 等等。

问题是,当我将 UserControl 包含到父视图中并将完整控件设置为 IsEnabled=False 时,该特定 UserControl 中的子控件仍处于启用状态。

毕竟我发现了问题。

添加类似的内容意味着IsEnabled 绑定位于UserControl 绑定中,而不是像我预期的那样位于父级的DataContext 中。

<localControls:TeamEmployeeSelector Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"
          IsEnabled="Binding CanModify" DataContext="Binding Confidentiality"/>

问题: 但是还有一个问题,我如何将IsEnabled 绑定到父视图模型?因为将CanModify属性复制到子控件的ViewModel中不是很优雅。

【问题讨论】:

【参考方案1】:

我不知道在 Silverlight 中是否可行,但在 WPF 中我会使用 RelativeSource。

看看here。

希望有帮助!

【讨论】:

【参考方案2】:
<localControls:TeamEmployeeSelector Grid.Row="1" Grid.Column="0"
Grid.ColumnSpan="2" IsEnabled="Binding ElementName=SomeElementName_With_Parent_ViewModel, Path=DataContext.CanModify" DataContext="Binding Confidentiality"/>

【讨论】:

【参考方案3】:

不是以某种方式修改绑定(例如,您可以使其依赖于其他答案中建议的其他控件名称),我将单独移动将被禁用的控件并控制DataContext 将被更改的位置.例如:

<ContentControl IsEnabled="Binding CanModify" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2">
    <localControls:TeamEmployeeSelector DataContext="Binding Confidentiality"/>
</ContentControl>

【讨论】:

嗨雪熊,这似乎是一个有效的解决方案。我明天试试。谢谢提示。【参考方案4】:

我会这样做。

您的 TeamEmployeeSelector UserControl 将包含一个根级元素,默认情况下为 Grid 并命名为“LayoutRoot”。

现在您可以将所有子元素的IsEnabled 属性绑定到UserControl,如下所示:-

 <TextBox IsEnabled="Binding Parent.IsEnabled, ElementName=LayoutRoot" ... />

通过使用元素到元素绑定,您无需将CanModify 属性复制到子视图模型中。

有些人可能会建议您只需将 x:Name 添加到您的 UserControl 元素,然后直接绑定到它,而不是像上面那样通过根元素的 Parent 属性。这在 Silverlight 4 中可以正常工作,但在 3 或 WP7 中不行。我个人更喜欢上面的。

【讨论】:

您好 Anothony,我现在没有尝试您的解决方案,但它似乎无法解决必须定位 CanModify 属性的问题。禁用用户控件的子控件不是问题,而是禁用用户控件本身。此 UserControl IsEnabled 绑定取决于 CanModify 属性,该属性实际上必须位于控件的视图模型中。这点让我很恼火......【参考方案5】:

这是一个范围界定问题。通常,在创建UserControl 时,您希望将其自身设置为其子元素的DataContext。这在构造函数中最容易实现:

UserControlExample() 
   InitializeComponent();
   RootElement.DataContext = this;

其中RootElement 是您给UserControl 的第一个孩子(通常是网格或面板)的名称。

您可以从这里为您的子元素设置自然绑定,如下所示:

<TextBox x:Name="MainTextBox" IsEnabled=Binding IsEnabled />

这是可行的,因为TextBox 继承了父布局面板的DataContext

最后,如果您想让UserControlIsEnabled 属性与其父级相关联,最好在声明时完成:

<Grid>
   <UserControlExample IsEnabled=Binding CanModify />
</Grid>

这样您就可以将您的顾虑分开。子控件不关心UserControl 反映的内容。他们只需要知道当控件的IsEnabled 属性翻转时如何启用/禁用。

sub-controls IsEnabled bound to --> (UserControlExample is DataContext)
   UserControlExample.IsEnabled bound to -->  (VM is DataContext)
      VM.CanModify  

【讨论】:

以上是关于将 IsEnabled 绑定到父 ViewModel 而不是 UserControl ViewModel的主要内容,如果未能解决你的问题,请参考以下文章

如何将 WPF ListBoxItem 的 IsEnabled 属性绑定到其源项的属性?

WPF 条件绑定。 Button.IsEnabled 到 SelectedIndex >= 0

将 UserControl ListBox ItemSsource 绑定到父 DataContext 时出错

C# WPF IsEnabled 使用多个绑定?

wpf usercontrol,将按钮的命令参数绑定到父用户控件

将多重绑定放在 xaml 中的单行上