How can I link to DisplayMemberPath inside an ItemTemplate?

2

I need to create a list type control that meets the following requirements:

  • Show an icon delete right next to the text of each item.
  • Must show the added elements horizontally.
  • When clicking on the delete icon, the control must be able to remove it from the ItemsSource, and these changes must also be reflected to the property to which the ItemsSource is linked.
  • Must always work, regardless of the type linked to the ItemsSource property of the control.

For this I have made a custom control that inherits from listview:

Imports System.Windows.Controls.Primitives
Imports System.Reflection

Public Class ListCustomControl
Inherits System.Windows.Controls.ListView

Shared Sub New()
    'Esta llamada a OverrideMetadata indica al sistema que este elemento desea proporcionar un estilo diferente al de su clase base.
    'Este estilo se define en themes\generic.xaml
    DefaultStyleKeyProperty.OverrideMetadata(GetType(ListCustomControl), New FrameworkPropertyMetadata(GetType(ListCustomControl)))
End Sub

Public Overrides Sub OnApplyTemplate()
    MyBase.OnApplyTemplate()
End Sub

Private Sub ListCustomControl_Loaded(sender As Object, e As System.Windows.RoutedEventArgs) Handles Me.Loaded
    AddHandler MyBase.PreviewMouseLeftButtonDown, AddressOf OnPreviewMouseLeftButtonDown
End Sub

Private Overloads Sub OnPreviewMouseLeftButtonDown(sender As Object, e As MouseButtonEventArgs)
    If e.OriginalSource.GetType Is GetType(Controls.Image) Then
        CType(Me.ItemsSource, IList).Remove(CType(e.OriginalSource, Image).DataContext)
    End If
End Sub
End Class 

Here's the generic.xaml associated with ListCustomControl:

<Style TargetType="{x:Type local:ListCustomControl}">
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
    <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
    <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
    <Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
    <Setter Property="ScrollViewer.PanningMode" Value="Both"/>
    <Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
    <Setter Property="VerticalContentAlignment" Value="Center"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:ListCustomControl}">
                <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="1" SnapsToDevicePixels="true">
                    <ScrollViewer Focusable="false" Padding="{TemplateBinding Padding}">
                        <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                    </ScrollViewer>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsEnabled" Value="false">
                        <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
                    </Trigger>
                    <Trigger Property="IsGrouping" Value="true">
                        <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="ItemTemplate" >
        <Setter.Value>
            <DataTemplate x:Name="ItemTemplate">
                <Border x:Name="Border"
                    Padding="2"
                    CornerRadius="5"
                    HorizontalAlignment="Left" VerticalAlignment="Top">
                    <Grid x:Name="LayoutGrid">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="Auto" />
                        </Grid.ColumnDefinitions>
                        <Label x:Name="LabelText"
                            Grid.Column="0"
                            Foreground="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=LabelTextColor}"
                            Content="{Binding Name}" 
                            Padding="2,0,2,0"
                            FontStyle="Italic" />
                        <Border x:Name="PART_IconBorder"
                            Grid.Column="1"
                            BorderThickness="1"
                            Background="White" 
                            VerticalAlignment="Top"
                            HorizontalAlignment="Left"
                            BorderBrush="White">
                            <Image x:Name="Icon"
                            Stretch="None"
                            HorizontalAlignment="Center"
                            VerticalAlignment="Center" 
                            Source="/ListCustomControl;component/Resources/Images/delete.gif" />
                        </Border>
                    </Grid>
                </Border>
            </DataTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="ItemsPanel">
        <Setter.Value>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal"></StackPanel>
            </ItemsPanelTemplate>
        </Setter.Value>
    </Setter>
</Style>

Everything works fulfilling the requested requirements, but I have one doubt:

How could I make the content of the labeltext work against the DisplayMemberPath property of ListCustomControl instead of being forced to bind it to the name property as it is now?

    
asked by Sergio Garcia 25.02.2016 в 17:04
source

1 answer

1

You should use something like this:

<Label Content="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListCustomControl}}, Path=DisplayMemberPath}"/>

What it does is look for the upper container that matches the 'ListCustomControl' type and take its 'DisplayMemberPath' property, as long as it is defined there, otherwise it will not show anything.

    
answered by 07.12.2016 в 12:48