Dependency Property Datacontext

孤者浪人 提交于 2019-12-11 02:06:48

问题


I have a usercontrol, and there is a Datacontext set for it. 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:

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


回答1:


You don't need to override the data context of user control . You can use RelativeSource to point your binding source property i.e. TimeValue to any other source you like. E.g. If you have the source property in your windows class. You could simply point your binding target to the source in window's data context as follows:

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

"Apologies for formatting . Typed from iPhone"




回答2:


Although this has now been solved there seems to be some, in my opinion, inappropriate use of the DataContext.

When developing a custom reusable control, you should not set DataContext at all. What the DataContext will be, that is for the user of the control to decide, not for the developer. 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. The developer of the control (in this case, the WPF team), didn't touch the DataContext at all - that is up to you. What does it mean for you as a control developer? Your DependencyProperty definition is fine, but you shouldn't touch the DataContext. How will you then bind something inside your control to the DependencyProperty value? 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).

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.

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). So the value goes like this: 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). 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. So the binding to TimeValue will look for it in the control instead (which will, of course, fail).

Just don't touch the DataContext when developing a control and you'll be fine.




回答3:


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. You must have somehow set the DataContext of the Window or UserControl that contains the 'TimePicker' object to an instance of the 'TimePicker' object.

Instead, it should be set to an instance of the class that declares the 'TimeValue' property. 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):

DataContext = this;

Please note that when data binding to the 'Time' property from inside your TimePicker control, you should use a RelativeSource Binding:

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



回答4:


Normally we are not setting datacontext directly.If u want to set datacontext create an instance of your usercontrol and set datacontext individually to each one.



来源:https://stackoverflow.com/questions/30476263/dependency-property-datacontext

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!