为啥在数据模板中使用 xaml UserControl 时无法绑定到依赖属性? [复制]

Posted

技术标签:

【中文标题】为啥在数据模板中使用 xaml UserControl 时无法绑定到依赖属性? [复制]【英文标题】:Why am I unable to bind to dependency properties in my xaml UserControl when using it in a data template? [duplicate]为什么在数据模板中使用 xaml UserControl 时无法绑定到依赖属性? [复制] 【发布时间】:2021-11-03 15:44:42 【问题描述】:

我正在尝试通过一些辅助项目来提高我的 WPF 技能 - 目前正在创建 Windows 文件资源管理器的小型克隆。

我目前正在做“这台电脑”部分 - 制作一个旨在模仿资源管理器显示磁盘方式的用户控件,即资源管理器有这个:

我的克隆有这个:

在这个用户控件(Drive.xaml & Drive.xaml.cs)中,我创建了几个我希望能够绑定到的依赖属性,以便传入数据,即卷标、磁盘名称、使用百分比等等……:

Drive.xaml.cs - 为简洁起见缩短

public partial class Drive : UserControl

    /// <summary>
    /// Using a DependencyProperty as the backing store for DriveName.  This enables animation, styling, binding, etc...
    /// </summary>
    public static readonly DependencyProperty DriveNameProperty =
        DependencyProperty.Register("DriveName", typeof(string), typeof(Drive), new PropertyMetadata(string.Empty));

        /// <summary>
        /// Initializes a new instance of the <see cref="Drive" /> class
        /// </summary>
        public Drive()
        
            this.InitializeComponent();
        

        /// <summary>
        /// Gets or sets the <see cref="DriveNameProperty" /> dependency property
        /// </summary>
        public string DriveName
        
            get => (string)this.GetValue(DriveNameProperty);
            set => this.SetValue(DriveNameProperty, value);
        
    

Drive.xaml - 也缩短了

<UserControl x:Class="Explorer.View.Components.Hardware.Drive"
             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" 
             DataContext="Binding RelativeSource=RelativeSource Self"
             d:DesignHeight="60" 
             d:DesignWidth="260">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="15"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="200" />
        </Grid.ColumnDefinitions>

        <Image Width="50" VerticalAlignment="Center" Grid.Row="0" Grid.Column="0" Grid.RowSpan="3" Source="StaticResource DriveIcon" />
        <TextBlock Grid.Row="0" Grid.Column="1">
            <TextBlock.Text>
                <MultiBinding StringFormat="0 (1)">
                    <Binding Path="VolumeLabel"/>
                    <Binding Path="DriveName"/>
                </MultiBinding>
            </TextBlock.Text>
        </TextBlock>
        <ProgressBar Grid.Row="1" Grid.Column="1" Value="Binding PercentageUsedBar" Foreground="CornflowerBlue" />
        <TextBlock Grid.Row="2" Grid.Column="1" Text="[x TB free of y TB]"/>
    </Grid>
</UserControl>

当我尝试将此控件用作数据模板的一部分时,我遇到了这个问题。我可以在不绑定的情况下使用这些依赖属性:

<!-- this works and renders correctly -->
<hardware:Drive PercentageUsedBar="25" DriveName="C:\" VolumeLabel="Reece"/>

但显然这并没有多大用处。所以我有一个 ViewModel,它提供来自文件系统的相关真实数据,并且我正在尝试绑定到其中的详细信息,以呈现连接到我的系统的所有磁盘:

<!-- this does not work for some reason -->
<ItemsControl ItemsSource="Binding FixedDrives">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Button Style="StaticResource TabButtonStyle">
                <hardware:Drive Margin="5" 
                                DriveName="Binding Drive.Name"
                                VolumeLabel="Binding Drive.VolumeLabel"
                                PercentageUsedBar="Binding PercentageSpaceUsed"/>
            </Button>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

但这只是让我每个磁盘的绑定失败:

任何帮助将不胜感激,我开始扯头发了!

【问题讨论】:

【参考方案1】:

您正在“覆盖”继承的DataContext

UserControl 中删除它,即不要明确设置它的DataContext

DataContext="Binding RelativeSource=RelativeSource Self"

...并指定每个绑定的来源:

<TextBlock Grid.Row="0" Grid.Column="1">
    <TextBlock.Text>
        <MultiBinding StringFormat="0 (1)">
            <Binding Path="VolumeLabel" RelativeSource="RelativeSource AncestorType=UserControl"/>
            <Binding Path="DriveName" RelativeSource="RelativeSource AncestorType=UserControl"/>
        </MultiBinding>
    </TextBlock.Text>
</TextBlock>

【讨论】:

就是这样!不知道即使梳理了一段时间我也没有把它捡起来。谢谢:)

以上是关于为啥在数据模板中使用 xaml UserControl 时无法绑定到依赖属性? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

为啥在 XAML 中绑定 MainWindow 数据上下文与使用 this.datacontext=this 在代码隐藏中绑定的行为不同?

将元素后面的代码注入 XAML 数据模板

Xamarin XAML语言教程控件模板的模板绑定

在 Generic.xaml 的模板化控件中应用默认样式

资源图像可以在 Xaml 中引用,但不能在代码中引用,为啥?

为啥我的 Asp.Net Core 日志中出现“不支持 POST 请求”?