要使用(DataContext的),或者不使用 [英] To use (DataContext) or not to use

查看:676
本文介绍了要使用(DataContext的),或者不使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有关于DataContext的两难境地。让我们来考察下面这段XAML的:

I've got a dilemma regarding the DataContext. Let's inspect the following piece of XAML:

<Window xmlns:my="clr-namespace:MyNamespace.Controls"
        ... >
    ...
    <my:MyControl Name="{Binding Prop1}" Value="{Binding Prop2}" />
</Window>

显然,窗口的code-背后包含类似:

Obviously, the Window's code-behind contains something like:

DataContext = someViewModel;

作者的意图是明确的 - 他要绑定 MyControl 名称窗口取值的的DataContext 为prop1 Prop2 。而这当然会工作。除非。 (戏剧性的沉默)

Author's intentions are clear - he wants to bind MyControl's Name and Value to Window's DataContext's Prop1 and Prop2. And this will of course work. Unless. (dramatic pause)

除非 MyControl 是一个复合用户控件,也想带绑定的简短表示法的优势,并将其的DataContext 来自己的视图模型。因为这时它会变得清晰,即在绑定窗口的 XAML实际上绑定到 MyControl 的DataContext 或(previously从窗口的中遗留的),现在他们将停止工作(糟糕的是,如果<$会继续努力C $ C> MyControl 的视图模型实际上包含命名属性为prop1 Prop2 1 )。

Unless MyControl is a composite UserControl, which also wants to take advantage of short notation of bindings and sets its DataContext to its own viewmodel. Because then it will become clear, that the bindings in Window's XAML actually bind to MyControl's DataContext (previously inherited from Window's one) and now they will stop working (or worse, will keep working if MyControl's viewmodel actually contains properties named Prop1 and Prop21).

在这种特殊情况下的解决方法是在窗口的code显式绑定:

In this particular case solution is to bind in Window's code explicitly:

<Window x:Name="rootControl"
        xmlns:my="clr-namespace:MyNamespace.Controls"
        ... >
    ...
    <my:MyControl Name="{Binding ElementName=rootControl, Path=DataContext.Prop1}" 
                  Value="{Binding ElementName=rootControl, Path=DataContext.Prop2}" />
</Window>

TL; DR 如果我们使用绑定的简短表示法(​​结合的DataContext 时),我们可能会遇到相当艰难钉导致错误从突然指着错误的绑定的DataContext

TL;DR If we're using short notation of bindings (when binding to DataContext) we may encounter quite tough to nail bugs resulting from bindings suddenly pointing to wrong DataContext.

我的问题是:如何利用短期没有风险约束符号,我会绑定到错误的的DataContext ?当然,我可以使用短符号的当我确定的,我将使用继承的DataContext 和长符号的当我敢肯定的,该控件将修改其的DataContext 。但是,我敢肯定的只会工作,直到第一个错误,这将消耗调试一个小时。

My question is: how to use short binding notation without risk, that I'll bind to wrong DataContext? Of course I may use the short notation when I'm sure, that I'll be using inherited DataContext and long notation when I'm sure, that control will modify its DataContext. But that "I'm sure" will work only until first mistake, which will consume another hour of debugging.

也许我不是遵循一些规则MVVM?例如。例如的DataContext 应该在顶层设置只有一次,所有的复合控件应该绑定到别的东西吗?

Maybe I'm not following some MVVM rule? E.g. for example DataContext should be set only once on the top level and all composited controls should bind to something else?



1 我通过了,其实。在窗口的DataContext 包含一个名为(说)道具属性和控制取代了的DataContext 带班,其中还包含一个属性道具和一切工作正常。当我试图用(不知不觉中)与非匹配属性名称相同的模式问题出现了。


1 I've gone through that, actually. The Window's DataContext contained a property named (say) Prop and the control replaced its DataContext with a class, which also contained a property Prop and everything worked fine. Problem appeared when I tried to use (unconsciously) the same pattern with non-matching property names.

通过要求:

MyControl的code的片段:

Fragment of MyControl's code:

    public string Name
    {
        get { return (string)GetValue(NameProperty); }
        set { SetValue(NameProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Name.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty NameProperty =
        DependencyProperty.Register("Name", typeof(string), typeof(MyControl), new PropertyMetadata(null));

    public int Value
    {
        get { return (int)GetValue(ValueProperty); }
        set { SetValue(ValueProperty, value); }
    }

    // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ValueProperty =
        DependencyProperty.Register("Value", typeof(int), typeof(MyControl), new PropertyMetadata(0));

窗口的视图模型:

Window's viewmodel:

public class WindowViewmodel : INotifyPropertyChanged
{
    // (...)

    public string Prop1
    {
        get
        {
            return prop1;
        }
        set
        {
            prop1 = value;
            OnPropertyChanged("Prop1");
        }
    }

    public int Prop2
    {
        get
        {
            return prop2;
        }
        set
        {
            prop2 = value;
            OnPropertyChanged("Prop2");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

现在假设,即在名称变更依赖属性, MyControl 生成一些视图模型并执行code:

Now assume, that on changing of Name and Value dependency properties, MyControl generates some viewmodel and executes the code:

model = new MyControlViewModel(Name, Value);
this.DataContext = model;

和内部 MyControl 控件绑定到这个DataContext的。

And internal MyControl controls bind to this DataContext.

从现在起,原名称绑定将不再起作用。

From now on, the original Name and Value bindings will no longer work.

推荐答案

您可以通过简单地解决问题的的使用你所谓的'复合控件。虽然我知道你是想封装在相关的视图模型的一些功能,你并不需要设置视图模型到 UserControl.DataContext 内部。

You can solve your problems by simply not using what you call a 'composite control. While I understand that you want to encapsulate some functionality in the associated view model, you don't need to set the view model to the UserControl.DataContext internally.

我的意思是,你的可以的有任何或所有的用户控件个视图模型,但它们数​​据类的,不是的 UI类的,所以保持他们走出视图code的。如果使用加入这种方法的DataTemplate s转换资源,那么你就不需要设置任何的DataContext 属性在所有:

What I mean by this is that you can have a view model for any or all of your UserControls, but they're data classes, not UI classes, so keep them out of the view code. If you use this method of adding DataTemplates into Resources, then you won't need to set any DataContext properties at all:

<DataTemplate DataType="{x:Type ViewModels:YourUserControlViewModel}">
    <Views:YourUserControl />
</DataTemplate>

最后的区别是,你应该在父视图模型属性的用户控件■添加您的视图模型。这样,你还是没有重复code(除也许只是一个财产申报),更重要的是,你有没有绑定从混合问题 DataContext的值。

The final difference is that you should add your view model for your UserControls as properties in a parent view model. This way, you still have no duplicated code (except maybe just a property declaration) and more importantly, you have no Binding problems from mixing DataContext values.

更新>>>

在使用本的DataTemplate 挂钩的观点和看法车型的方法,可以显示由视图绑定您视图模型属性设置为内容的属性 ContentControl中是这样的:

When using this DataTemplate method of hooking up views and view models, you can display your view by Binding your view model property to the Content property of a ContentControl like this:

<ContentControl Content="{Binding YourViewModelProperty}" />

在运行时,这个 ContentControl中将呈现为任何视图或用户控件您在<$定义相关类型该属性的C $ C>的DataTemplate 。请注意,你不应该设置 X:键的DataTemplate ,否则你还需要设置 ContentControl.ContentTemplate 属性和可以限制通过这种方法提供的可能性。

At run time, this ContentControl will be rendered as whatever view or UserControl that you defined in the DataTemplate of the relevant type for that property. Note that you shouldn't set the x:Key of the DataTemplate, otherwise you'd also need to set the ContentControl.ContentTemplate property and that can limit the possibilities afforded by this method.

例如,的没有的设置 X:键的DataTemplate 财产,你可以有一个基本类型的属性,将其设置为不同的子类,可以从有一个 ContentControl中为每个不同的看法。这是所有我的意见的基础上...我有约束这样的例子一个基类视图模型数据的一个属性,并改变看法,我只是属性更改为从基类派生的新的视图模式。

For example, without setting the x:Key property on your DataTemplates, you could have a property of a base type and by setting it to different sub class, you can have different views for each from the one ContentControl. That is the basis of all of my views... I have one property of a base class view model data bound like this example and to change views, I just change the property to a new view model that is derived from the base class.

更新2 >>>

这里的东西...你不应该在你的用户控件在做任何事情代理对象...它应该的所有通过属性来完成。所以刚才宣布的对象类型的的DependencyProperty 和视图模型通过数据绑定供给。这样做,这样意味着它会很容易测试类的功能,而测试code后面的观点是没有的。

Here's the thing... you shouldn't have any 'proxy' object in your UserControls doing anything... it should all be done through properties. So just declare a DependencyProperty of the type of that object and supply it from the view model through data Binding. Doing it this way means that it will be easy to test the functionality of that class, whereas testing code behind views is not.

最后,是的,这是完全罚款MVVM这样做的:

And finally, yes, it's perfectly fine doing this in MVVM:

<Controls:SomeUserControl DataContext="{Binding SomeViewModelProperty}" />

MVVM的首要目标就是为客户提供UI code和视图模型code之间的分离,这样我们就可以很方便地测试什么的视图模型。这就是为什么我们试图从视图中删除尽可能多的功能code。

The overriding goal of MVVM is just to provide separation between the UI code and the view model code, so that we can easily test what's in the view models. That is why we try to remove as much functionality code from the views as possible.

这篇关于要使用(DataContext的),或者不使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆