依赖属性Datacontext

时间:2015-05-27 07:50:20

标签: c# wpf dependency-properties

我有一个usercontrol,并为它设置了一个Datacontext。此usercontrol还包含Dependency-Property。现在,我想简单地绑定到这个属性。

我认为这个问题与错误的datacontext有关。

我的usercontrol中的dependency-Property(称为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));

我试着像这样使用它:

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

当我这样做时,我得到以下绑定错误:

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')

任何帮助都将受到高度赞赏

问候迈克尔

PS:您可以在here

下载代码

4 个答案:

答案 0 :(得分:3)

虽然现在已经解决了这个问题,但在我看来,似乎有些人不恰当地使用DataContext

开发自定义可重用控件时,不应设置DataContextDataContext将是什么,即控件的用户决定的,而不是开发人员。考虑以下常见的代码模式:

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

请注意,您在使用Grid控件。控件的开发人员(在本例中是WPF团队)根本没有触及DataContext - 这取决于您。作为控制开发人员,对您来说意味着什么?您的DependencyProperty定义没问题,但您不应该触及DataContext。然后,您将如何将控件内的某些内容绑定到DependencyProperty值?一个好方法是使用模板(省略名称空间):

<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>

请注意,TemplateBinding始终是单向的,因此如果您需要进行任何编辑,则需要使用常规绑定(如示例中的TextBox所示)。 / p>

这仅表示您控件中的TextBlock / Box将从您的自定义控件本身获取其Time值,而忽略您可能设置的任何DataContext

然后,当你使用控件时,你就这样做了(添加到我的第一个例子中):

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

这里发生的事情是MyTimePicker根本没有设置DataContext - 它从父控件(Grid)获取。所以价值如下:Data-->(binding)-->MyTimePicker.Time-->(template binding)-->TextBlock.Text

最重要的是,避免在自定义控件的构造函数中执行此操作:

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

这将覆盖XAML中设置的任何DataContext,这将使绑定变得非常痛苦(因为您必须始终手动设置Source)。前面的例子不起作用,这也不会起作用:

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

您会认为这没关系,但DataContext将在InitializeComponent()调用中得到解决,因此该值将立即被覆盖。因此,绑定到TimeValue将在控件中查找它(当然,这将失败)。

在制作控件时,请勿触摸DataContext,否则你会没事的。

答案 1 :(得分:2)

您无需覆盖用户控件的数据上下文。您可以使用RelativeSource将绑定源属性(即TimeValue)指向您喜欢的任何其他源。 例如。如果您的Windows类中有source属性。您可以简单地将绑定目标指向窗口数据上下文中的源,如下所示:

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

“格式化道歉。从iPhone输入”

答案 2 :(得分:1)

您的错误指出'TimePicker'上找不到'TimeValue'属性,这意味着WPF框架正在查看.thumbnail{ .... background-size: cover; } 对象以解析{{1 }} 适当的价值。您必须以某种方式将包含'TimePicker'对象的'TimeValue'DataContext的{​​{1}}设置为Window对象的实例。

相反,它应该设置为声明UserControl属性的类的实例。如果您正在使用视图模型,则应将其设置为该实例:

'TimePicker'

如果'TimePicker''TimeValue'中声明了DataContext = new YourViewModel(); 属性,那么您可以将'TimeValue'设置为自身(虽然通常不推荐):

Window

请注意,当数据绑定到UserControl控件中的DataContext属性时,您应该使用DataContext = this;

'Time'

答案 3 :(得分:0)

通常我们不直接设置datacontext。如果你想设置datacontext,你可以创建一个usercontrol的实例,并为每个实例分别设置datacontext。