#wpf #xaml #user-controls #datatemplate
#wpf #xaml #пользовательские элементы управления #datatemplate
Вопрос:
Я хотел бы создать UserControl, у которого есть DataTemplate, а внутри этого DataTemplate есть элементы управления. Я хотел бы привязаться к этим вложенным свойствам элементов управления (внутри DataTemplate), чтобы я мог устанавливать их при повторном использовании этого UserControl. Вложенные элементы управления будут использовать свойства ItemSource, но имена свойств свойств ItemSource могут отличаться.
UserControl:
<UserControl x:Class="ContextMenu.BaseFilterUserControl"
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"
x:Name="Self">
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="70" />
</Grid.RowDefinitions>
<TextBlock Grid.Column="0"
VerticalAlignment="Center"
HorizontalAlignment="Right"
Margin="10"
Text="Owners" />
<Button Grid.Column="1"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Margin="10"
Click="FilteButtonClicked"
Width="40"
Height="40"
x:Name="FilterButton">
<Popup x:Name="FilterBoxPopup"
PlacementTarget="{Binding ElementName=FilterButton}"
Placement="Bottom"
StaysOpen="False">
<Border BorderBrush="Black"
Background="White"
Margin="2">
<ListView ItemsSource="{Binding ElementName=Self, Path=FilterList}"
x:Name="FilterListView"
Height="300"
Width="150">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<!--<CheckBox IsChecked="{Binding IsChecked}" />-->
<!--<TextBlock Text="{Binding Name}" />-->
<!--This is where I don't know how to properly bind eg. the above control, things I tried:-->
<!--<TextBlock Text="{Binding ElementName=FilterListView, Path=FilterElementName}" />-->
<!--<TextBlock Text="{Binding ElementName=Self, Path=DataContext.FilterElementName}" />-->
<!--<TextBlock Text="{Binding ElementName=FilterListView, Path=DataContext.FilterElementName}" />-->
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Border>
</Popup>
</Button>
<TextBlock Grid.Column="3"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="10"
Text="{Binding ElementName=Self, Path=SelectedNames}" />
</Grid>
</UserControl>
Это то, как используется UserControl, FilterElementName=»Name» — это то, что я хотел бы установить, в зависимости от списка, привязанного к списку FilterList:
<local:BaseFilterUserControl FilterList="{Binding Owners}"
FilterElementName="Name"
SelectedNames="{Binding SelectedNames}"/>
В этом случае Owners — это простой IReadOnlyList класса Owner. Класс Owner имеет свойство string Name. Но я буду использовать этот UserControl снова с другим списком, например. где я хотел бы использовать свойство Release списка версий (для текстового блока внутри UserControl):
<local:BaseFilterUserControl FilterList="{Binding Versions}"
FilterElementName="Release"
SelectedNames="{Binding SelectedReleases}"/>
ListView правильно заполнен элементами, поэтому свойство FilterList DependencyProperty работает. Но вложенные элементы управления работают только тогда, когда я жестко кодирую привязки:
<TextBlock Text="{Binding Name}" />
Ответ №1:
Для этого вам нужно было бы привязать свойство Path вашей текстовой привязки TextBlocks к свойству FilterElementName вашего UserControl. К сожалению, свойство Path класса Binding не является DependencyProperty и, следовательно, не может быть привязано.
Одним из способов достижения вашей цели было бы использовать свойство DisplayMemberPath ListView, которое является привязываемым:
<ListView x:Name="FilterListView"
Width="150"
Height="300"
ItemsSource="{Binding ElementName=Self, Path=FilterList}"
DisplayMemberPath="{Binding ElementName=self, Path=FilterElementName}"/>
Если этот подход не работает, потому что вам нужно указать более сложный ItemTemplate, другим способом было бы создать свойство типа DataTemplate в вашем UserControl, используйте это как ItemTemplate в ListView и укажите его извне следующим образом:
<local:BaseFilterUserControl FilterList="{Binding Versions}"
SelectedNames="{Binding SelectedReleases}">
<local:BaseFilterUserControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Release}" />
</DataTemplate>
</local:BaseFilterUserControl.ItemTemplate>
</local:BaseFilterUserControl>