简体   繁体   English

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

[英]Creating UserControl via MVVM pattern - DataContext and binding to parent

I use MVVM pattern so my own control contains View and ViewModel. 我使用MVVM模式,所以我自己的控件包含View和ViewModel。
ViewModel is connected with View by DataContext property. ViewModel与View by DataContext属性相关联。 This makes problems with binding. 这会产生绑定问题。 Why? 为什么?

Assume this situation: 假设这种情况:
I created new user control - for example - "SuperTextBox". 我创建了新的用户控件 - 例如 - “SuperTextBox”。 It have a property "SuperValue". 它有一个属性“SuperValue”。
And now I do something like that: 现在我做了类似的事情:

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

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

I thought that "binding process" joins SuperTextBox.SuperValue with Window.DataContext.Test, but no, 'binding process" joins SuperTextBox.SuperValue with SuperTextBox.DataContext.Test what is for me unnatural and misleading. 我认为“绑定进程”将SuperTextBox.SuperValue与Window.DataContext.Test连接起来,但是没有,“绑定进程”将SuperTextBox.SuperValue与SuperTextBox.DataContext.Test连接起来对我来说不自然和误导。

Other controls like "TextBox" I can use in above way because they do not have their DataContext. 像TextBox这样的其他控件我可以用上面的方式,因为它们没有DataContext。

How can I use MVVM pattern to creating UserControls keeping natural binding (to DataContext of parent control) ? 如何使用MVVM模式创建保持自然绑定的UserControl(对于父控件的DataContext)?

Edit: 编辑:

I got many answers how binding to parent, but I know this earlier. 我得到了许多答案,如何绑定父母,但我早先知道。 The problem is - how can I create UserControl via MVVM patern (having ViewModel) and stay natural binding - default to parent DataContext. 问题是 - 如何通过MVVM patern(具有ViewModel)创建UserControl并保持自然绑定 - 默认为父DataContext。

I want to have ViewMoldel and still can binding like this: 我想拥有ViewMoldel,仍然可以像这样绑定:

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

Is it possible? 可能吗?

All bindings applied on any control always first look for the binding in its DataContext . 应用于任何control always first look for the binding in its DataContext所有绑定control always first look for the binding in its DataContext In case the DataContext is not set for the control, then it walks up the Visual Tree upto its parent unless it finds the DataContext. 如果未为控件设置DataContext,则它会将walks up the Visual Tree到其父级,除非它找到DataContext。

Even if you set the DataContext on your textBox to some value different than of Window's DatContext, it will always search for property Test on that particular DataContext and not on your Window's DataContext . 即使您将textBox上的DataContext设置为与Window的DatContext不同的某个值,它也将始终在该特定DataContext上搜索属性Test ,而不是在Window's DataContext

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

Now, xaml will look for Test property in class ViewModelForTextBox instead in class WindowViewModel and if Test property is not found in class ViewModelForTextBox , binding will fail silently and won't look up to the Window's DataContext class. 现在,xaml将在类ViewModelForTextBox查找Test属性,而不是在WindowViewModel类中查找,如果在ViewModelForTextBox类中找不到Test属性, binding will fail silently并且不会查找Window的DataContext类。

In case you still want to set the DataContext for your Custom UserControl but still want to bind to the parent's (Window) dataContext, you have to use the RelativeSource MarkupExtension in your bindings like this - 如果您仍想为自定义UserControl设置DataContext但仍希望绑定到父级(Window)dataContext,则必须在绑定中使用RelativeSource MarkupExtension ,如下所示 -

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

Refer to the MSDN article here for more clarification. 有关更多说明,请参阅此处的MSDN文章。

you should post your SuperTextBox code, because there is your error. 你应该发布你的SuperTextBox代码,因为你的错误。

usually you create a usercontrol with a dependency property - in your case "SuperValue" - and now the most important thing you do not set the datacontext of your SuperTextBox to it self. 通常你创建一个带有依赖属性的usercontrol - 在你的情况下是“SuperValue” - 现在最重要的是你没有将SuperTextBox的datacontext设置为自己。

you have to use elementname binding within your SuperTextBox to bind to "SuperValue" 你必须在你的SuperTextBox中使用elementname绑定来绑定到“SuperValue”

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

if you do this that way - your 如果你这样做 - 你的

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

should work and should bind to the Test Property of your vm:WindowViewModel. 应该工作,并应绑定到您的vm:WindowViewModel的测试属性。 thats the only way to write the binding like above. 这是编写如上所述的绑定的唯一方法。

EDIT: if you wanna create a viewmodel for your usercontrol, let say SuperTextViewmodel. 编辑:如果你想为你的usercontrol创建一个viewmodel,那就说SuperTextViewmodel。 then it would have a property "SuperValue". 然后它会有一个属性“SuperValue”。 now you cant set the datacontext twice so i would suggest you have to add a Property to your WindowViewmodel of type SuperTextViewmodel and handle the properties like you want. 现在你不能设置datacontext两次所以我建议你必须在你的WindowTem模型中添加一个属性SuperTextViewmodel并处理你想要的属性。

your binding the looks like this 你的绑定看起来像这样

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

i would go with my first part of the answer :) i always say a view need a viewmodel but a usercontrol dependency properties. 我会回答我的第一部分答案:)我总是说一个视图需要一个viewmodel但是一个usercontrol依赖属性。

You need to "Look up" the datacontext of it's window ancestor. 你需要“查找”它的窗口祖先的datacontext。 Your binding would look like this: 你的绑定看起来像这样:

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

I feel oddly answering on my question but... 我觉得奇怪地回答我的问题,但......
In my own control i did something like that: 在我自己的控制下,我做了类似的事情:

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

Now I can use "natural" binding outside of control and in control. 现在我可以在控制之外和控制之外使用“自然”绑定。 :) :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM