依赖项 属性 用户控件绑定不起作用
Dependency Property UserControl Binding not working
我的项目是用MVVM实现的。我有一个主窗口,它由一个状态栏和一个选项卡视图组成。在 tabview 中,有一个名为 "AnnotationView" 的 UserControl。 Annotationview 是两个较小的用户控件的父控件,称为 TimePicker。 TimePicker 由两个文本框组成,一个用于小时,一个用于分钟。我想使用此 UserControl 两次(这也是我将其设为自己的控件以便稍后重用的原因)。
XAML 的 TimePicker:
<UserControl x:Class="archidb.Views.TimePicker"
x:Name="TimePickerControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" Height="Auto" Width="Auto"
KeyboardNavigation.TabNavigation="Local">
<Grid DataContext="{Binding ElementName=TimePickerControl}">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="5"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBox Style="{StaticResource TextBoxStyle}"
Text="{Binding Path=HourValue}"
x:Name="tbHours"
KeyboardNavigation.TabIndex="0"/>
<TextBlock Style="{StaticResource TextBlockStyle}"
Margin="0 -3 0 5"
Text=":"
Grid.Column="1"/>
<TextBox Grid.Column="2" Style="{StaticResource TextBoxStyle}"
Text="{Binding Path=MinuteValue}"
x:Name="tbMinutes"
KeyboardNavigation.TabIndex="1"/>
</Grid>
</UserControl>
TimePicker 代码隐藏:
public partial class TimePicker : UserControl
{
public static readonly DependencyProperty HourValueProperty = DependencyProperty.Register("HourValue", typeof(string), typeof(TimePicker), new PropertyMetadata("00"));
public string HourValue
{
get { return (string)GetValue(HourValueProperty); }
set { SetValue(HourValueProperty, value); }
}
public static readonly DependencyProperty MinuteValueProperty = DependencyProperty.Register("MinuteValue", typeof(string), typeof(TimePicker), new PropertyMetadata("00"));
public string MinuteValue
{
get { return (string)GetValue(MinuteValueProperty); }
set { SetValue(MinuteValueProperty, value); }
}
public TimePicker()
{
InitializeComponent();
}
}
在 AnnotationControl 中,我像这样插入 UserControl:
<v:TimePicker x:Name="tpStart"
HourValue="{Binding Path=StartHours}"
MinuteValue="{Binding Path=StartMinutes}"
KeyboardNavigation.TabIndex="2"/>
<v:TimePicker x:Name="tpEnde"
HourValue="{Binding Path=EndHours}"
MinuteValue="{Binding Path=EndMinutes}"
KeyboardNavigation.TabIndex="3"
Grid.Row="2"/>
AnnotationControl 的 DataContext 设置为其视图模型,我在其中声明了属性。
问题是,绑定不起作用。我在依赖项 属性 ("00") 中设置的默认值没有显示在任何文本框中。此外,如果我在文本框中写了一些东西,AnnotationControl 视图模型中的 属性 不会更改其值。这个问题已经困扰我好几天了,我到底做错了什么?
首先,在 UserControl 构造函数中,将 DataContext 设置为其自身:
public TimePicker()
{
InitializeComponent();
this.DataContext = this;
}
此外,从用户控件的网格中删除它:
DataContext="{Binding ElementName=TimePickerControl}"
您的用户控件的 DataContext 已在用户控件本身内设置,因此当您使用以下代码时:
HourValue="{Binding Path=EndHours}"
你其实是在问"Bind to EndHours in the UserControl's DataContext."
您需要更改绑定,以便它查看父级的 DataContext window。给父项 window 一个名称并使用以下内容:
HourValue="{Binding DataContext.EndHours, ElementName=windowName}"
最简单的方法:
删除该行:
DataContext="{Binding ElementName=TimePickerControl}"
这样绑定:
"{Binding ElementName=TimePickerControl, Path=HourValue}"
另一种方式:(更清洁)
在TimePicker构造函数中设置:
(this.Content as FrameworkElement).DataContext = this;
这样绑定:
"{Binding HourValue}"
经过一些阅读,您的示例应该可以工作,所以我假设您没有为您的 ViewModel 实现 INotifyPropertyChanged,“00”没有显示,因为绑定有效,属性设置为默认值并且它们的值没有更新。
解决方案是简单地在 UserControl
中使用 RelativeSource Binding
并且 不将它的 DataContext
设置为它自己 :
在你的控制之下:
<TextBox Style="{StaticResource TextBoxStyle}" Text="{Binding HourValue, RelativeSource=
{RelativeSource AncestorType={x:Type YourPrefixToBeAdded:TimePickerControl}}}"
x:Name="tbHours" KeyboardNavigation.TabIndex="0" />
<TextBlock Style="{StaticResource TextBlockStyle}" Margin="0 -3 0 5" Text=":"
Grid.Column="1" />
<TextBox Grid.Column="2" Style="{StaticResource TextBoxStyle}" Text="{Binding
MinuteValue, RelativeSource={RelativeSource AncestorType={x:Type
YourPrefixToBeAdded:TimePickerControl}}}" x:Name="tbMinutes"
KeyboardNavigation.TabIndex="1" />
然后您将能够从控件外部对属性进行数据绑定。
我的项目是用MVVM实现的。我有一个主窗口,它由一个状态栏和一个选项卡视图组成。在 tabview 中,有一个名为 "AnnotationView" 的 UserControl。 Annotationview 是两个较小的用户控件的父控件,称为 TimePicker。 TimePicker 由两个文本框组成,一个用于小时,一个用于分钟。我想使用此 UserControl 两次(这也是我将其设为自己的控件以便稍后重用的原因)。
XAML 的 TimePicker:
<UserControl x:Class="archidb.Views.TimePicker"
x:Name="TimePickerControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" Height="Auto" Width="Auto"
KeyboardNavigation.TabNavigation="Local">
<Grid DataContext="{Binding ElementName=TimePickerControl}">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="5"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBox Style="{StaticResource TextBoxStyle}"
Text="{Binding Path=HourValue}"
x:Name="tbHours"
KeyboardNavigation.TabIndex="0"/>
<TextBlock Style="{StaticResource TextBlockStyle}"
Margin="0 -3 0 5"
Text=":"
Grid.Column="1"/>
<TextBox Grid.Column="2" Style="{StaticResource TextBoxStyle}"
Text="{Binding Path=MinuteValue}"
x:Name="tbMinutes"
KeyboardNavigation.TabIndex="1"/>
</Grid>
</UserControl>
TimePicker 代码隐藏:
public partial class TimePicker : UserControl
{
public static readonly DependencyProperty HourValueProperty = DependencyProperty.Register("HourValue", typeof(string), typeof(TimePicker), new PropertyMetadata("00"));
public string HourValue
{
get { return (string)GetValue(HourValueProperty); }
set { SetValue(HourValueProperty, value); }
}
public static readonly DependencyProperty MinuteValueProperty = DependencyProperty.Register("MinuteValue", typeof(string), typeof(TimePicker), new PropertyMetadata("00"));
public string MinuteValue
{
get { return (string)GetValue(MinuteValueProperty); }
set { SetValue(MinuteValueProperty, value); }
}
public TimePicker()
{
InitializeComponent();
}
}
在 AnnotationControl 中,我像这样插入 UserControl:
<v:TimePicker x:Name="tpStart"
HourValue="{Binding Path=StartHours}"
MinuteValue="{Binding Path=StartMinutes}"
KeyboardNavigation.TabIndex="2"/>
<v:TimePicker x:Name="tpEnde"
HourValue="{Binding Path=EndHours}"
MinuteValue="{Binding Path=EndMinutes}"
KeyboardNavigation.TabIndex="3"
Grid.Row="2"/>
AnnotationControl 的 DataContext 设置为其视图模型,我在其中声明了属性。
问题是,绑定不起作用。我在依赖项 属性 ("00") 中设置的默认值没有显示在任何文本框中。此外,如果我在文本框中写了一些东西,AnnotationControl 视图模型中的 属性 不会更改其值。这个问题已经困扰我好几天了,我到底做错了什么?
首先,在 UserControl 构造函数中,将 DataContext 设置为其自身:
public TimePicker()
{
InitializeComponent();
this.DataContext = this;
}
此外,从用户控件的网格中删除它:
DataContext="{Binding ElementName=TimePickerControl}"
您的用户控件的 DataContext 已在用户控件本身内设置,因此当您使用以下代码时:
HourValue="{Binding Path=EndHours}"
你其实是在问"Bind to EndHours in the UserControl's DataContext."
您需要更改绑定,以便它查看父级的 DataContext window。给父项 window 一个名称并使用以下内容:
HourValue="{Binding DataContext.EndHours, ElementName=windowName}"
最简单的方法: 删除该行:
DataContext="{Binding ElementName=TimePickerControl}"
这样绑定:
"{Binding ElementName=TimePickerControl, Path=HourValue}"
另一种方式:(更清洁)
在TimePicker构造函数中设置:
(this.Content as FrameworkElement).DataContext = this;
这样绑定:
"{Binding HourValue}"
经过一些阅读,您的示例应该可以工作,所以我假设您没有为您的 ViewModel 实现 INotifyPropertyChanged,“00”没有显示,因为绑定有效,属性设置为默认值并且它们的值没有更新。
解决方案是简单地在 UserControl
中使用 RelativeSource Binding
并且 不将它的 DataContext
设置为它自己 :
在你的控制之下:
<TextBox Style="{StaticResource TextBoxStyle}" Text="{Binding HourValue, RelativeSource=
{RelativeSource AncestorType={x:Type YourPrefixToBeAdded:TimePickerControl}}}"
x:Name="tbHours" KeyboardNavigation.TabIndex="0" />
<TextBlock Style="{StaticResource TextBlockStyle}" Margin="0 -3 0 5" Text=":"
Grid.Column="1" />
<TextBox Grid.Column="2" Style="{StaticResource TextBoxStyle}" Text="{Binding
MinuteValue, RelativeSource={RelativeSource AncestorType={x:Type
YourPrefixToBeAdded:TimePickerControl}}}" x:Name="tbMinutes"
KeyboardNavigation.TabIndex="1" />
然后您将能够从控件外部对属性进行数据绑定。