[英]Misunderstanding databinding fundamentals and DataContexts — long story
我一直在几种简单的情况下使用数据绑定,并取得了很好的成功。 通常,我只是使用INotifyPropertyChanged来启用我的代码隐藏功能来修改屏幕上的GUI值,而不是为所有内容实现依赖项属性。
我正在玩LED控件,以了解有关用户控件中数据绑定的更多信息,并且由于VS2008告诉我必须这样做,因此不得不使用依赖项属性。 我的应用程序很简单-我有一个窗口,其中显示几个LED控件,每个控件上方都有一个数字,还可以在侧面显示一个。 LED应使用默认颜色以及更改状态进行定义。
我首先编写了一个LED控件,看起来还不错。 首先,我从这样的代码开始:
LED.xaml
<UserControl x:Class="LEDControl.LED"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="Auto" Width="Auto">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<!-- LED portion -->
<Ellipse Grid.Column="0" Margin="3" Height="{Binding LEDSize}" Width="{Binding LEDSize}" Fill="{Binding LEDColor}" StrokeThickness="2" Stroke="DarkGray" />
<Ellipse Grid.Column="0" Margin="3" Height="{Binding LEDSize}" Width="{Binding LEDSize}">
<Ellipse.Fill>
<RadialGradientBrush GradientOrigin="0.5,1.0">
<RadialGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform CenterX="0.5" CenterY="0.5" ScaleX="1.5" ScaleY="1.5"/>
<TranslateTransform X="0.02" Y="0.3"/>
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<GradientStop Offset="1" Color="#00000000"/>
<GradientStop Offset="0.4" Color="#FFFFFFFF"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
<!-- label -->
<TextBlock Grid.Column="1" Margin="3" VerticalAlignment="Center" Text="{Binding LEDLabel}" />
</Grid>
</UserControl>
这样就可以画一个LED了。 然后,通过设置this.DataContext = this
像我一直一样,将LEDSize,LEDLabel和LEDColor绑定到Ellipse属性。
LED.xaml.cs
/// <summary>
/// Interaction logic for LED.xaml
/// </summary>
public partial class LED : UserControl, INotifyPropertyChanged
{
private Brush state_color_;
public Brush LEDColor
{
get { return state_color_; }
set {
state_color_ = value;
OnPropertyChanged( "LEDColor");
}
}
private int led_size_;
public int LEDSize
{
get { return led_size_; }
set {
led_size_ = value;
OnPropertyChanged( "LEDSize");
}
}
private string led_label_;
public string LEDLabel
{
get { return led_label_; }
set {
led_label_ = value;
OnPropertyChanged( "LEDLabel");
}
}
public LED()
{
InitializeComponent();
this.DataContext = this;
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged( string property_name)
{
if( PropertyChanged != null)
PropertyChanged( this, new PropertyChangedEventArgs( property_name));
}
#endregion
}
在这一点上,我可以更改属性值,并看到LED更改大小,颜色及其标签。 大!
我希望LED控件可以随着时间的推移在其他小部件中重复使用,而我的下一步是创建另一个名为IOView
UserControl(在单独的程序IOView
。 IOView
在这一点上非常基础:
IOView.xaml
<UserControl x:Class="IOWidget.IOView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:led="clr-namespace:LEDControl;assembly=LEDControl"
Height="Auto" Width="Auto">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" HorizontalAlignment="Center" Text="{Binding Path=Index}" />
<led:LED Grid.Row="1" HorizontalContentAlignment="Center" HorizontalAlignment="Center" LEDSize="30" LEDColor="Green" LEDLabel="Test" />
</Grid>
</UserControl>
请注意,我可以在设计时修改XAML中的LED属性,一切都会按预期进行:
然后,我盲目地尝试将LEDColor数据绑定到我的IOView,VS2008友好地告诉我“不能在类型为“ LED”的“ LEDColor”属性上设置“绑定”。只能在DependencyObject的DependencyProperty上设置“ Binding” “。 哎呀! 我什至没有意识到,因为我以前没有做过自己的GUI控件。 由于LEDColor
已经与Ellipse进行数据绑定,因此我添加了一个名为Color的DependencyProperty。
LED.xaml.cs
public static DependencyProperty ColorProperty = DependencyProperty.Register( "Color", typeof(Brush), typeof(LED));
public Brush Color
{
get { return (Brush)GetValue(ColorProperty); }
set {
SetValue( ColorProperty, value);
LEDColor = value;
}
}
请注意,我在设置器中设置了属性LEDColor
,因为这就是Ellipse知道其应为哪种颜色的方式。
下一步是通过绑定到IOView.InputColor设置IOView中LED的颜色:
IOView.xaml.cs:
/// <summary>
/// Interaction logic for IOView.xaml
/// </summary>
public partial class IOView : UserControl, INotifyPropertyChanged
{
private Int32 index_;
public Int32 Index
{
get { return index_; }
set {
index_ = value;
OnPropertyChanged( "Index");
}
}
private Brush color_;
public Brush InputColor
{
get { return color_; }
set {
color_ = value;
OnPropertyChanged( "InputColor");
}
}
private Boolean state_;
public Boolean State
{
get { return state_; }
set {
state_ = value;
OnPropertyChanged( "State");
}
}
public IOView()
{
InitializeComponent();
this.DataContext = this;
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged( string property_name)
{
if( PropertyChanged != null)
PropertyChanged( this, new PropertyChangedEventArgs( property_name));
}
#endregion
}
在IOView.xaml中,我将LED更改为此:
<led:LED Grid.Row="1" HorizontalContentAlignment="Center" HorizontalAlignment="Center" LEDSize="30" Color="{Binding InputColor}" />
但这不起作用,因为“输出”窗口中出现以下错误:
BindingExpression路径错误:在“对象”“ LED”(Name =“)”上找不到“ InputColor”属性。 BindingExpression:路径= InputColor; DataItem ='LED'(Name =''); 目标元素是'LED'(Name =''); 目标属性为“颜色”(类型为“画笔”)
嗯...由于某种原因,我的DataBinding搞砸了。 我可以使LED与数据绑定一起独立工作,但是一旦将它包装在另一个控件中并设置了它的datacontext后,它就不起作用了。 我不确定目前该如何尝试。
我希望得到尽可能详细的答案。 我知道我可以重新设计一个CheckBox以获得相同的结果,但这对我来说是一个实验,我试图了解如何将数据绑定到控件的后代。
关于这一切,有很多要说的,但让我看看我是否可以提供解决您一些误解的指针:
UserControl
本身中设置UserControl
的DataContext
被认为是不好的做法,因为UserControl
任何使用者都可以更改它,并且这样做会破坏控件中依赖于该上下文的任何绑定。 InputColor
未成功绑定的问题。 InputColor
属性位于主机控件( IOView
)提供的数据上下文中,但是LED的数据上下文设置为LED本身,因此,如果不进一步限制绑定,就无法找到该属性。 遵循此建议可导致以下实现(未经测试):
LED.xaml.cs :
public partial class LED : UserControl
{
public static readonly DependencyProperty LEDColorProperty = DependencyProperty.Register(
"LEDColor",
typeof(Brush),
typeof(LED));
public Brush LEDColor
{
get { return this.GetValue(LEDColorProperty) as Brush; }
set { this.SetValue(LEDColorProperty, value); }
}
// LEDSize and LEDLabel omitted for brevity, but they're very similar to LEDColor
public LED()
{
InitializeComponent();
}
}
LED.xaml :
<UserControl
x:Name="root"
x:Class="LEDControl.LED"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="Auto" Width="Auto">
<Grid DataContext="{Binding ElementName=root}>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<!-- LED portion -->
<Ellipse Grid.Column="0" Margin="3" Height="{Binding LEDSize}" Width="{Binding LEDSize}" Fill="{Binding LEDColor}" StrokeThickness="2" Stroke="DarkGray" />
<Ellipse Grid.Column="0" Margin="3" Height="{Binding LEDSize}" Width="{Binding LEDSize}">
<Ellipse.Fill>
<RadialGradientBrush GradientOrigin="0.5,1.0">
<RadialGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform CenterX="0.5" CenterY="0.5" ScaleX="1.5" ScaleY="1.5"/>
<TranslateTransform X="0.02" Y="0.3"/>
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<GradientStop Offset="1" Color="#00000000"/>
<GradientStop Offset="0.4" Color="#FFFFFFFF"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
<!-- label -->
<TextBlock Grid.Column="1" Margin="3" VerticalAlignment="Center" Text="{Binding LEDLabel}" />
</Grid>
</UserControl>
IOView.xaml :
<UserControl x:Name="root"
x:Class="IOWidget.IOView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:led="clr-namespace:LEDControl;assembly=LEDControl"
Height="Auto" Width="Auto">
<Grid DataContext="{Binding ElementName=root}">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" HorizontalAlignment="Center" Text="{Binding Path=Index}" />
<led:LED Grid.Row="1" HorizontalContentAlignment="Center" HorizontalAlignment="Center" LEDSize="{Binding I_Can_Bind_Here_All_I_Like}" LEDColor="{Binding I_Can_Bind_Here_All_I_Like}" LEDLabel="{Binding I_Can_Bind_Here_All_I_Like}" />
</Grid>
</UserControl>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.