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

How to bind to properties of a UserControl inside another UserControl?

我有一个显示图标和文本的简单 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 使用正确。

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

默认情况下(并且您没有指定任何其他内容)绑定是从对象 DataContext 解析的。因此,您的 IconLabelDataContext.

上搜索名称为 IconPath 的 属性

要指定搜索属性的地方是外部控件,可以在绑定中添加ElementName并在[=15=上设置名称属性 ] 或者您指定一个 RelativeSource 就像在 How do I use WPF bindings with RelativeSource.

中接受的答案的第二个例子

希望对您有所帮助。

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

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

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

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

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


与其显式设置 UserControl 的 DataContext,不如将其 "internal" 绑定写入 RelativeSource,如

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