简体   繁体   English

依赖属性数据上下文

[英]Dependency Property Datacontext

I have a usercontrol, and there is a Datacontext set for it. 我有一个用户控件,并且有一个Datacontext设置。 This usercontrol contains also a Dependency-Property. 此用户控件还包含一个依赖项属性。 Now, i want simply bind to this property. 现在,我只想绑定到此属性。

I think the problem has something to do with the wrong datacontext. 我认为问题与错误的数据上下文有关。

The dependency-Property in my usercontrol (called TimePicker) looks like this: 我的用户控件(称为TimePicker)中的依赖项属性如下所示:

public TimeSpan Time
    {
        get { return (TimeSpan)GetValue(TimeProperty); }
        set
        {
            SetValue(TimeProperty, value);
            OnPropertyChanged();
        }
    }

    public static readonly DependencyProperty TimeProperty = DependencyProperty.Register("Time", typeof (TimeSpan), typeof (TimePicker));

I try to use it like this: 我尝试像这样使用它:

<upDownControlDevelopement:TimePicker Grid.Row="1" Time="{Binding Path=TimeValue}" />

When i do this i get the following binding error: 当我这样做时,我得到以下绑定错误:

System.Windows.Data Error: 40 : BindingExpression path error: 'TimeValue' property not found on 'object' ''TimePicker' (Name='TimePickerControl')'. BindingExpression:Path=TimeValue; DataItem='TimePicker' (Name='TimePickerControl'); target element is 'TimePicker' (Name='TimePickerControl'); target property is 'Time' (type 'TimeSpan')

Any help would be highly appreciated 任何帮助将不胜感激

Greetings Michael 迈克尔的问候

PS: you can download the code at here PS:您可以在此处下载代码

Although this has now been solved there seems to be some, in my opinion, inappropriate use of the DataContext . 尽管现在已经解决了这个问题,但在我看来,似乎似乎不恰当地使用了DataContext

When developing a custom reusable control, you should not set DataContext at all. 在开发自定义可重用控件时,根本不要设置DataContext What the DataContext will be, that is for the user of the control to decide, not for the developer. DataContext是什么,即由控件的用户决定,而不是由开发人员决定。 Consider the following common pattern of code: 考虑以下常见的代码模式:

<Grid DataContext="{Binding Data}">
    <TextBox Text="{Binding TextValue1}" />
    <!-- Some more controls -->
</Grid>

Notice that here, you are using the Grid control. 请注意,这里您正在使用Grid控件。 The developer of the control (in this case, the WPF team), didn't touch the DataContext at all - that is up to you. 控件的开发人员(在本例中为WPF团队)完全没有涉及DataContext这取决于您。 What does it mean for you as a control developer? 作为控件开发人员,这对您意味着什么? Your DependencyProperty definition is fine, but you shouldn't touch the DataContext . 您的DependencyProperty定义很好,但是您不应碰触DataContext How will you then bind something inside your control to the DependencyProperty value? 然后,如何将控件内部的某些内容绑定到DependencyProperty值? A good way is using a template (namespaces omitted): 一个好的方法是使用模板(省略命名空间):

<MyTimePicker>
    <MyTimePicker.Template>
        <ControlTemplate TargetType="MyTimePicker">
            <!-- Stuff in your control -->
            <TextBlock Text="{TemplateBinding Time}" />
            <TextBox Text="{Binding Time, RelativeSource={RelativeSource TemplatedParent}}" />
        </ControlTemplate>
    <MyTimePicker.Template>
</MyTimePicker>

Note that TemplateBinding is always one-way only, so if you need any editing at all, you need to use normal binding (as you can see on the TextBox in the example). 请注意, TemplateBinding始终仅是单向的,因此,如果您根本需要进行任何编辑,则需要使用常规绑定(如示例中的TextBox所示)。

This only means that the TextBlock/Box inside your control will get its Time value from your custom control itself, ignoring any DataContext you might have set. 这仅意味着控件内的TextBlock / Box将从您的自定义控件本身获取其Time值,而忽略您可能已设置的任何DataContext

Then, when you use the control, you do it like this (added to my first example): 然后,当您使用控件时,您可以像这样操作(添加到我的第一个示例中):

<Grid DataContext="{Binding Data}">
    <TextBox Text="{Binding TextValue1}" />
    <!-- Some more controls -->
    <MyTimePicker Time="{Binding TimeValue}" />
</Grid>

What just happened here is that the MyTimePicker does not have DataContext set anywhere at all - it gets it from the parent control (the Grid ). 此处发生的只是MyTimePicker根本没有设置DataContext -它是从父控件( Grid )获取的。 So the value goes like this: Data-->(binding)-->MyTimePicker.Time-->(template binding)-->TextBlock.Text . 因此该值如下所示: Data-->(binding)-->MyTimePicker.Time-->(template binding)-->TextBlock.Text

And above all, avoid doing this in the constructor of your custom control: 最重要的是,避免在自定义控件的构造函数中执行此操作:

public MyTimePicker()
{
    InitializeComponent();
    DataContext = this;
}

This will override any DataContext set in XAML, which will make binding a huge pain (because you'll have to always set Source manually). 这将覆盖XAML中设置的任何DataContext ,这将使绑定非常麻烦(因为您必须始终手动设置Source )。 The previous example would not work, and this wouldn't work either: 前面的示例不起作用,并且也不起作用:

<MyTimePicker DataContext="{Binding Data}" Time="{Binding TimeValue}" />

You would think this is OK, but the DataContext will be resolved in the InitializeComponent() call, so the value will be immediately overwritten. 您可能认为可以,但是DataContext将在InitializeComponent()调用中解析,因此该值将立即被覆盖。 So the binding to TimeValue will look for it in the control instead (which will, of course, fail). 因此,与TimeValue的绑定将改为在控件中查找(当然,它将失败)。

Just don't touch the DataContext when developing a control and you'll be fine. 只需在开发控件时不要接触DataContext ,就可以了。

You don't need to override the data context of user control . 您无需覆盖用户控件的数据上下文。 You can use RelativeSource to point your binding source property ie TimeValue to any other source you like. 您可以使用RelativeSource将绑定源属性(即TimeValue)指向您喜欢的任何其他源。 Eg If you have the source property in your windows class. 例如,如果您在Windows类中具有source属性。 You could simply point your binding target to the source in window's data context as follows: 您可以简单地将绑定目标指向window数据上下文中的源,如下所示:

 {Binding Path=DataContext.TimeValue, RelativeSource={ RelativeSource AncestorType={x:Type Window}}}

"Apologies for formatting . Typed from iPhone" “格式的道歉。从iPhone键入。”

Your error states that 'TimeValue' property not found on 'object' 'TimePicker' , which means that the WPF Framework is looking at the 'TimePicker' object to resolve the 'TimeValue' property value. 您的错误指出在“对象”“ TimePicker”上找不到“ TimeValue”属性 ,这意味着WPF框架正在查看'TimePicker'对象以解析'TimeValue'属性值。 You must have somehow set the DataContext of the Window or UserControl that contains the 'TimePicker' object to an instance of the 'TimePicker' object. 你必须以某种方式设置DataContext的的WindowUserControl包含'TimePicker'对象的实例'TimePicker'对象。

Instead, it should be set to an instance of the class that declares the 'TimeValue' property. 而是应将其设置为声明'TimeValue'属性的类的实例。 If you're using a view model, then you should set it to an instance of that: 如果使用的是视图模型,则应将其设置为该视图的实例:

DataContext = new YourViewModel();

If the 'TimeValue' property is declared in the Window or UserControl then you can set the DataContext to itself (although generally not recommended): 如果在WindowUserControl声明了'TimeValue'属性,则可以将DataContext设置为其自身(尽管通常不建议这样做):

DataContext = this;

Please note that when data binding to the 'Time' property from inside your TimePicker control , you should use a RelativeSource Binding : 请注意, TimePicker控件内部将数据绑定到'Time'属性时,应使用RelativeSource Binding

<TextBlock Text="{Binding Time, RelativeSource={RelativeSource 
    AncestorType={x:Type YourLocalPrefix:TimePicker}}}" ... />

通常情况下,我们不是直接设置datacontext。如果要设置datacontext,请创建您的usercontrol的实例,并将datacontext分别设置为每个实例。

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

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