如何绑定到另一个UserControl内的UserControl的属性?

时间:2016-12-03 16:52:58

标签: wpf vb.net xaml user-controls

我有一个显示图标和文字的简单UserControl

<UserControl x:Class="IconLabel"
         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" 
         d:DesignHeight="26" d:DesignWidth="200" DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="1*"/>
        </Grid.ColumnDefinitions>
        <Image x:Name="imgIcon" Source="{Binding Path=IconPath}" Stretch="UniformToFill" Width="26" Height="26" Margin="3,0" />
        <Label Content="{Binding Path=LabelText}" Margin="5,0" Grid.Column="1" />
    </Grid>
</UserControl>

代码隐藏定义了两个意图从外部绑定的DependencyProperties

Public Class IconLabel

    Public Property IconPath As String
        Get
            Return GetValue(IconPathProperty)
        End Get
        Set(ByVal value As String)
            SetValue(IconPathProperty, value)
        End Set
    End Property

    Public Shared ReadOnly IconPathProperty As DependencyProperty = DependencyProperty.Register("IconPath", GetType(String), GetType(IconLabel), New PropertyMetadata(""))

    Public Property LabelText As String
        Get
            Return GetValue(LabelTextProperty)
        End Get
        Set(ByVal value As String)
            SetValue(LabelTextProperty, value)
        End Set
    End Property

    Public Shared ReadOnly LabelTextProperty As DependencyProperty = DependencyProperty.Register("LabelText", GetType(String), GetType(IconLabel), New PropertyMetadata("LabelText"))
End Class

到目前为止工作正常。我可以在XAML中设置它的属性,它们正在被正确使用:

<local:IconLabel LabelText="Test"/>

但是,我现在想在另一个UserControl中重新使用此控件,通过在其旁边显示一个进度条来略微扩展其功能(为了示例,我保留了这个简短的内容) :

<UserControl x:Class="IconLabelProgress"
         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" 
         xmlns:local="clr-namespace:myApp"
         mc:Ignorable="d" 
         d:DesignHeight="26" d:DesignWidth="600" DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="4*" MaxWidth="300"/>
            <ColumnDefinition Width="6*"/>
        </Grid.ColumnDefinitions>
        <local:IconLabel IconPath="{Binding Path=IconPath}" LabelText="{Binding Path=PropName}" />
        <ProgressBar Value="{Binding Path=ActualValue}" Minimum="0" Maximum="10" Margin="5" Height="16" VerticalAlignment="Top" Grid.Column="1" />
    </Grid>
</UserControl>

使用以下代码隐藏:

Public Class IconLabelProgress

    'These are just meant to be passed along to the IconLabel
    Public Property IconPath As String
        Get
            Return GetValue(IconPathProperty)
        End Get
        Set(ByVal value As String)
            SetValue(IconPathProperty, value)
        End Set
    End Property

    Public Shared ReadOnly IconPathProperty As DependencyProperty = DependencyProperty.Register("IconPath", GetType(String), GetType(IconLabelProgress), New PropertyMetadata(""))

    Public Property PropName As String
        Get
            Return GetValue(PropNameProperty)
        End Get
        Set(ByVal value As String)
            SetValue(PropNameProperty, value)
        End Set
    End Property

    Public Shared ReadOnly PropNameProperty As DependencyProperty = DependencyProperty.Register("PropName", GetType(String), GetType(IconLabelProgress), New PropertyMetadata("PropName"))

    'This one is new
    Public Property ActualValue As Double
        Get
            Return GetValue(ActualValueProperty)
        End Get
        Set(ByVal value As Double)
            SetValue(ActualValueProperty, value)
        End Set
    End Property

    Public Shared ReadOnly ActualValueProperty As DependencyProperty = DependencyProperty.Register("ActualValue", GetType(Double), GetType(IconLabelProgress), New PropertyMetadata(0.0))
End Class

如果我现在尝试实例化此控件并传入内部IconLabel控件的标签值,如下所示:

<local:IconLabelProgress x:Name="ilp1" PropName="Test" ActualValue="5.0" />

然后它不会在其标签上显示“Test”,而是回退到通过PropertyMetadata("LabelText")指定的默认值。但是ActualValue使用正确。

如何让外部控件将值传递给嵌套的?

2 个答案:

答案 0 :(得分:2)

作为一般规则,永远不要像使用

那样显式设置UserControl的DataContext属性
<UserControl x:Class="IconLabel" ...
    DataContext="{Binding RelativeSource={RelativeSource Self}}">

这样做可以有效地防止从UserControl的父级继承DataContext,例如这里

<local:IconLabel LabelText="{Binding Path=PropName}" ... />

其中PropName应该是父DataContext中的属性。

不要明确设置UserControl&#39; DataContext,而是写出&#34;内部&#34;绑定RelativeSource喜欢

<Label Content="{Binding Path=LabelText,
                 RelativeSource={RelativeSource AncestorType=UserControl}}" ... />

答案 1 :(得分:0)

默认情况下(并且您没有指定任何其他内容),绑定将从对象DataContext中解析出来。因此,IconLabel会在IconPath上搜索名称为DataContext的媒体资源。

要指定搜索属性的位置是外部控件,您可以将ElementName添加到绑定并在IconLabelProgress上设置名称属性,或者指定RelativeSource就像How do I use WPF bindings with RelativeSource中接受的答案的第二个例子一样。

希望它有所帮助。