And my clone has this:
In this user control (Drive.xaml
& Drive.xaml.cs
), I have created several dependency properties that I want to be able to bind to in order to pass data in, namely being the volume label, disk name, percentage used etc...:
Drive.xaml.cs
- shortened for brevity
public partial class Drive : UserControl
{
public static readonly DependencyProperty DriveNameProperty =
DependencyProperty.Register("DriveName", typeof(string), typeof(Drive), new PropertyMetadata(string.Empty));
public Drive()
{
this.InitializeComponent();
}
public string DriveName
{
get => (string)this.GetValue(DriveNameProperty);
set => this.SetValue(DriveNameProperty, value);
}
}
Drive.xaml
- also shortened
<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>
The issue I'm having arises when I try to use this control as part of a data template. I can use these dependency properties without binding:
<hardware:Drive PercentageUsedBar="25" DriveName="C:\" VolumeLabel="Reece"/>
But obviously that's not much use. So I have a ViewModel that provides the relevant real data from the filesystem, and I'm attempting to bind to details from that in order to render all the disks attached to my system:
<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>
But this just gives me binding failures for each disk:
Any help would be greatly appreciated, I'm starting to tear my hair out!
CodePudding user response:
You are "overriding" the inherited DataContext
.
Remove this from the UserControl
, i.e. do not set its DataContext
explicitly:
DataContext="{Binding RelativeSource={RelativeSource Self}}"
...and specify the source of each binding:
<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>