我有一个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
下载代码答案 0 :(得分:3)
虽然现在已经解决了这个问题,但在我看来,似乎有些人不恰当地使用DataContext
。
开发自定义可重用控件时,不应设置DataContext
。 DataContext
将是什么,即控件的用户决定的,而不是开发人员。考虑以下常见的代码模式:
<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)
您的错误指出
相反,它应该设置为声明UserControl
属性的类的实例。如果您正在使用视图模型,则应将其设置为该实例:
'TimePicker'
如果'TimePicker'
或'TimeValue'
中声明了DataContext = new YourViewModel();
属性,那么您可以将'TimeValue'
设置为自身(虽然通常不推荐):
Window
请注意,当数据绑定到UserControl
控件中的DataContext
属性时,您应该使用DataContext = this;
:
'Time'
答案 3 :(得分:0)
通常我们不直接设置datacontext。如果你想设置datacontext,你可以创建一个usercontrol的实例,并为每个实例分别设置datacontext。