WPF DataTemplate内使用自定义UserControl时依赖属性绑定失败如何解决
你遇到的绑定错误根因是你在自定义Drive UserControl的XAML根节点硬编码了DataContext="{Binding RelativeSource={RelativeSource Self}}",这会导致控件的DataContext永远指向自身实例,而不会继承外层DataTemplate提供的列表项数据上下文,因此外部绑定时无法找到Drive.Name、PercentageSpaceUsed等属于业务ViewModel的属性。
解决方案1(推荐):移除UserControl的硬编码DataContext,修改内部绑定路径
- 首先删除
Drive.xaml根节点的DataContext="{Binding RelativeSource={RelativeSource Self}}"属性 - 将控件内部所有绑定都显式指定绑定源为控件本身,修改后的
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" 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" RelativeSource="{RelativeSource AncestorType=UserControl}"/> <Binding Path="DriveName" RelativeSource="{RelativeSource AncestorType=UserControl}"/> </MultiBinding> </TextBlock.Text> </TextBlock> <ProgressBar Grid.Row="1" Grid.Column="1" Value="{Binding PercentageUsedBar, RelativeSource={RelativeSource AncestorType=UserControl}}" Foreground="CornflowerBlue" /> <TextBlock Grid.Row="2" Grid.Column="1" Text="[x TB free of y TB]"/> </Grid> </UserControl>
这种方案符合WPF自定义控件的最佳实践,不会破坏控件外层的DataContext继承逻辑,外部使用时的绑定写法不需要做任何修改。
解决方案2(临时兼容,不推荐):外部绑定时显式指定数据源
如果你暂时不想修改UserControl的内部代码,可以在外部绑定的时候显式指定从DataTemplate的父级取数据上下文,修改绑定写法如下:
<hardware:Drive Margin="5" DriveName="{Binding DataContext.Drive.Name, RelativeSource={RelativeSource AncestorType=ItemsControl}}" VolumeLabel="{Binding DataContext.Drive.VolumeLabel, RelativeSource={RelativeSource AncestorType=ItemsControl}}" PercentageUsedBar="{Binding DataContext.PercentageSpaceUsed, RelativeSource={RelativeSource AncestorType=ItemsControl}}"/>
这种写法会增加外部使用的复杂度,还会带来不必要的绑定查找开销,仅适合临时测试使用。
内容的提问来源于stack exchange,提问作者Reece
相关产品推荐
相关产品推荐

