4

我使用 MVVM 模式,所以我自己的控件包含 View 和 ViewModel。
ViewModel 通过 DataContext 属性与 View 连接。这会导致绑定问题。为什么?

假设这种情况:
我创建了新的用户控件——例如——“SuperTextBox”。它有一个属性“SuperValue”。
现在我做这样的事情:

<Window>
    <Window.DataContext>
        <vm:WindowViewModel/>
    </Window.DataContext>

    <local:SuperTextBox SuperValue="{Binding Test}"/>
</Window>

我认为“绑定过程”将 SuperTextBox.SuperValue 与 Window.DataContext.Test 结合起来,但不,“绑定过程”将 SuperTextBox.SuperValue 与 SuperTextBox.DataContext.Test 结合起来,这对我来说是不自然和误导的。

我可以以上述方式使用其他控件,例如“TextBox”,因为它们没有 DataContext。

如何使用 MVVM 模式创建保持自然绑定的用户控件(到父控件的 DataContext)?

编辑:

我得到了很多关于如何绑定到父母的答案,但我更早知道这一点。问题是 - 我如何通过 MVVM 模式(具有 ViewModel)创建 UserControl 并保持自然绑定 - 默认为父 DataContext。

我想要 ViewMoldel 并且仍然可以像这样绑定:

<local:SuperTextBox SuperValue="{Binding Test}"/>

可能吗?

4

4 回答 4

3

所有绑定都应用于任何control always first look for the binding in its DataContext. 如果没有为控件设置 DataContext,则walks up the Visual Tree除非找到 DataContext,否则它会一直到其父级。

即使您将DataContext文本框TestWindow's DataContext

<TextBox>
   <TextBox.DataContext>
      <vm:ViewModelForTextBox/>
   </TextBox.DataContext>
   <TextBox.Text>
      <Binding Path="Test"/>
   </TextBox.Text>
</TextBox>

现在,xaml 将在 class 中而不是在 class中查找Test属性,如果在 class 中找不到属性,则不会查找 Window 的 DataContext 类。ViewModelForTextBoxWindowViewModelTestViewModelForTextBoxbinding will fail silently

如果您仍想为自定义 UserControl 设置 DataContext 但仍想绑定到父级(窗口)的 dataContext,则必须RelativeSource MarkupExtension像这样在绑定中使用 -

<local:SuperTextBox SuperValue="{Binding Path=DataContext.Test,
                                RelativeSource={RelativeSource Mode=FindAncestor,
                                                 AncestorType={x:Type Window}}}">

请参阅此处的 MSDN 文章以获得更多说明。

于 2012-10-21T07:42:25.753 回答
2

你应该发布你的 SuperTextBox 代码,因为有你的错误。

通常你创建一个具有依赖属性的用户控件 - 在你的情况下是“SuperValue” - 现在最重要的是你没有将你的 SuperTextBox 的数据上下文设置为它自己。

您必须在 SuperTextBox 中使用 elementname 绑定才能绑定到“SuperValue”

 <SuperTextBox x:Name="uc">
   <TextBox Text="{Binding ElementName=uc, Path=SuperValue}/>
 </superTextBox>

如果你这样做 - 你的

 <local:SuperTextBox SuperValue="{Binding Test}"/>

应该可以工作并且应该绑定到您的 vm:WindowViewModel 的测试属性。这是编写上述绑定的唯一方法。

编辑:如果你想为你的用户控件创建一个视图模型,让我们说 SuperTextViewmodel。那么它将有一个属性“SuperValue”。现在你不能设置数据上下文两次,所以我建议你必须向你的 SuperTextViewmodel 类型的 WindowViewmodel 添加一个属性,并像你想要的那样处理属性。

你的绑定看起来像这样

 <local:SuperTextBox DataContext="{Binding MySuperTextViewmodelInstanceOnWindowViewmodel}"/>

我会回答我的第一部分:) 我总是说视图需要一个视图模型,但需要一个用户控件依赖属性。

于 2012-10-21T08:37:12.873 回答
1

您需要“查找”它的窗口祖先的数据上下文。您的绑定将如下所示:

<local:SuperTextBox SuperValue="{Binding Path=DataContext.Test, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}">
于 2012-10-21T02:01:17.243 回答
1

我觉得奇怪地回答了我的问题,但是......
在我自己的控制下,我做了这样的事情:

<UserControl>
    <Grid>
        <Grid.DataContext>
             <vm:UserControlViewModel />
        </Grid.DataContext>
        // here realy code of control
    </Grid>
</UserControl>

现在我可以在控制之外使用“自然”绑定。:)

于 2012-11-03T02:13:37.947 回答