通过MVVM模式创建UserControl - DataContext并绑定到父级

时间:2012-10-21 00:34:45

标签: c# wpf mvvm binding user-controls

我使用MVVM模式,所以我自己的控件包含View和ViewModel ViewModel与View by DataContext属性相关联。这会产生绑定问题。为什么?

假设这种情况:
我创建了新的用户控件 - 例如 - “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模式创建保持自然绑定的UserControl(对于父控件的DataContext)?

编辑:

我得到了许多答案,如何绑定父母,但我早先知道。问题是 - 如何通过MVVM patern创建UserControl(具有ViewModel)并保持自然绑定 - 默认为父DataContext。

我想拥有ViewMoldel并且仍然可以这样绑定:

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

有可能吗?

4 个答案:

答案 0 :(得分:2)

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

即使您将textBox上的DataContext设置为与Window的DatContext不同的值,它也将始终在该特定DataContext上搜索属性Test,而不是Window's DataContext上的属性<TextBox> <TextBox.DataContext> <vm:ViewModelForTextBox/> </TextBox.DataContext> <TextBox.Text> <Binding Path="Test"/> </TextBox.Text> </TextBox>

Test

现在,xaml将在类ViewModelForTextBox中查找WindowViewModel属性,而不是在类Test中找到ViewModelForTextBox属性,而在binding will fail silently类中找不到RelativeSource MarkupExtension属性,{ {1}}并且不会查看Window的DataContext类。

如果您仍想为自定义UserControl设置DataContext但仍希望绑定到父级(Window)dataContext,则必须在绑定中使用<local:SuperTextBox SuperValue="{Binding Path=DataContext.Test, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"> ,如下所示 -

{{1}}

有关更多说明,请参阅MSDN文章here

答案 1 :(得分:1)

你需要“查找”它的窗口祖先的datacontext。你的绑定看起来像这样:

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

答案 2 :(得分:1)

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

通常你创建一个带有依赖项属性的usercontrol - 在你的情况下是“SuperValue” - 现在最重要的是你没有将SuperTextBox的datacontext设置为自己。

你必须在SuperTextBox中使用elementname绑定来绑定到“SuperValue”

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

如果你这样做 - 你的

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

应该可以工作,并且应该绑定到vm:WindowViewModel的Test属性。这就是唯一方式来编写如上所述的绑定。

编辑:如果你想为你的usercontrol创建一个viewmodel,那就说SuperTextViewmodel。然后它会有一个属性“SuperValue”。现在你不能设置datacontext两次所以我建议你必须在你的类型为SuperTextViewmodel的WindowView模型中添加一个属性,并处理你想要的属性。

你的绑定看起来像这样

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

我会回答我的第一部分答案:)我总是说视图需要一个viewmodel但是一个usercontrol依赖属性。

答案 3 :(得分:1)

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

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

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