WPF-如何通过少量更改重构多个 ListViewItem 样式模板?

WPF- How to refactor multiple ListViewItem Style Template with few changes?

我在列表视图中使用自定义样式选择器来更改第一个和最后一个项目的 CornerRadius / BorderThickness。

我需要在列表视图上使用枚举绑定进行演示

带 ItemContainerStyleSelector 的列表视图代码

<ListView ItemsSource="{Binding ItemsSource, ElementName=Self, Mode=TwoWay}" 
              FocusVisualStyle="{x:Null}"
              BorderThickness="0"
              SelectedValue="{Binding SelectedValue, ElementName=Self, Mode=TwoWay}" 
              HorizontalAlignment="Stretch"
              ScrollViewer.VerticalScrollBarVisibility="Disabled"
              ScrollViewer.HorizontalScrollBarVisibility="Disabled"
              Background="Transparent">
            <ListView.ItemContainerStyleSelector>
                <enumToggleButtonList:FirstLastItemStyleSelector 
                    DefaultStyle="{StaticResource AllItemStyle}"
                    StyleFirst="{StaticResource FirstItemStyle}" 
                    StyleLast="{StaticResource LastItemStyle}"/>
            </ListView.ItemContainerStyleSelector>
            <ListView.ItemsPanel>
                <ItemsPanelTemplate>
                    <UniformGrid FlowDirection="LeftToRight" Rows="1"/>
                </ItemsPanelTemplate>
            </ListView.ItemsPanel>
        </ListView>

我有 3 种样式:默认/第一个/最后一个像这样

        <Style x:Key="AllItemStyle" TargetType="ListViewItem">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ListViewItem">
                        <Border x:Name="TemplateBorder" 
                                Style="{StaticResource BorderListViewItemStyle}" 
                                CornerRadius="0" 
                                BorderThickness="1,1,0,1">
                            <TextBlock x:Name="TemplateTextBlock" 
                                       Text="{Binding}" 
                                       Style="{StaticResource TextblockListViewItemStyle}"/>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsSelected" Value="True">
                                <Setter TargetName="TemplateBorder" Property="Style" Value="{StaticResource SelectedBorderListViewItemStyle}"/>
                                <Setter TargetName="TemplateTextBlock" Property="Style" Value="{StaticResource SelectedTextblockListViewItemStyle}"/>
                            </Trigger>
                            <Trigger Property="IsSelected" Value="False">
                                <Setter  TargetName="TemplateBorder" Property="Style" Value="{StaticResource BorderListViewItemStyle}"/>
                                <Setter TargetName="TemplateTextBlock" Property="Style" Value="{StaticResource TextblockListViewItemStyle}"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <EventSetter Event="PreviewMouseLeftButtonDown" Handler="ListViewItem_PreviewMouseLeftButtonDown" />
        </Style>
        <Style x:Key="LastItemStyle" TargetType="ListViewItem">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ListViewItem">
                        <Border x:Name="TemplateBorder" 
                                Style="{StaticResource BorderListViewItemStyle}" 
                                CornerRadius="0,5,5,0">
                            <TextBlock x:Name="TemplateTextBlock"
                                       Text="{Binding}" 
                                       Style="{StaticResource TextblockListViewItemStyle}"/>
                        </Border>
                        .... same
        </Style>
        <Style x:Key="FirstItemStyle" TargetType="ListViewItem">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ListViewItem">
                        <Border x:Name="TemplateBorder" 
                                Style="{StaticResource BorderListViewItemStyle}" 
                                CornerRadius="5,0,0,5" 
                                BorderThickness="1,1,0,1">
                            <TextBlock x:Name="TemplateTextBlock" 
                                       Text="{Binding}" 
                                       Style="{StaticResource TextblockListViewItemStyle}"/>
                        </Border>
                       .... same
        </Style>

全局更改是针对边界的:

 <Border x:Name="TemplateBorder" 
                                Style="{StaticResource BorderListViewItemStyle}" 
                                CornerRadius="5,0,0,5" 
                                BorderThickness="1,1,0,1">

有什么方法可以在不使用代码隐藏的情况下重构它吗?或者另一种方法?

您可以使用附加属性来简化您的样式。但这确实需要您创建一个简单的附加属性 class.

using System.Windows;

namespace SO
{
    public static class ListViewItemProperties
    {
        public static readonly DependencyProperty CornerRadiusProperty =
            DependencyProperty.RegisterAttached(
                "CornerRadius",
                typeof(Thickness),
                typeof(ListViewItemProperties),
                new PropertyMetadata(new Thickness(0d)));

        public static Thickness GetCornerRadius(DependencyObject obj)
        {
            return (Thickness)obj.GetValue(CornerRadiusProperty);
        }

        public static void SetCornerRadius(DependencyObject obj, Thickness value)
        {
            obj.SetValue(CornerRadiusProperty, value);
        }
    }
}

还有更新的(和简化的)样式使用附加的 属性:

<Style x:Key="AllItemStyle" TargetType="ListViewItem">
    <Setter Property="local:ListViewItemProperties.CornerRadius" Value="0" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ListViewItem">
                <Border x:Name="TemplateBorder"
                    BorderThickness="1,1,0,1"
                    CornerRadius="{TemplateBinding local:ListViewItemProperties.CornerRadius}"
                    Style="{StaticResource BorderListViewItemStyle}">
                    <TextBlock x:Name="TemplateTextBlock"
                        Style="{StaticResource TextblockListViewItemStyle}"
                        Text="{Binding}" />
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsSelected" Value="True">
                        <Setter TargetName="TemplateBorder" Property="Style" Value="{StaticResource SelectedBorderListViewItemStyle}" />
                        <Setter TargetName="TemplateTextBlock" Property="Style" Value="{StaticResource SelectedTextblockListViewItemStyle}" />
                    </Trigger>
                    <Trigger Property="IsSelected" Value="False">
                        <Setter TargetName="TemplateBorder" Property="Style" Value="{StaticResource BorderListViewItemStyle}" />
                        <Setter TargetName="TemplateTextBlock" Property="Style" Value="{StaticResource TextblockListViewItemStyle}" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <EventSetter
        Event="PreviewMouseLeftButtonDown"
        Handler="ListViewItem_PreviewMouseLeftButtonDown" />
</Style>

<Style x:Key="LastItemStyle" BasedOn="{StaticResource AllItemStyle}" TargetType="ListViewItem">
    <Setter Property="local:ListViewItemProperties.CornerRadius" Value="0,5,5,0" />
</Style>

<Style x:Key="FirstItemStyle" BasedOn="{StaticResource AllItemStyle}" TargetType="ListViewItem">
    <Setter Property="local:ListViewItemProperties.CornerRadius" Value="5,0,0,5" />
</Style>

目前最简单/性感的解决方案是 TemplateBinding ...我刚刚发现它是如何工作的...学习很难..但之后的方式更容易 x)

<Style x:Key="AllItemStyle" TargetType="ListViewItem">
    <Setter Property="Border.CornerRadius" Value="0"/>
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ListViewItem">
                <Border x:Name="TemplateBorder" 
                        Style="{StaticResource BorderListViewItemStyle}" 
                        CornerRadius="{TemplateBinding Border.CornerRadius}"
                        BorderThickness="{TemplateBinding BorderThickness}">
                    <TextBlock x:Name="TemplateTextBlock" 
                               Text="{Binding}" 
                               Style="{StaticResource TextblockListViewItemStyle}"/>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsSelected" Value="True">
                        <Setter TargetName="TemplateBorder" Property="Style" Value="{StaticResource SelectedBorderListViewItemStyle}"/>
                        <Setter TargetName="TemplateTextBlock" Property="Style" Value="{StaticResource SelectedTextblockListViewItemStyle}"/>
                    </Trigger>
                    <Trigger Property="IsSelected" Value="False">
                        <Setter  TargetName="TemplateBorder" Property="Style" Value="{StaticResource BorderListViewItemStyle}"/>
                        <Setter TargetName="TemplateTextBlock" Property="Style" Value="{StaticResource TextblockListViewItemStyle}"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <EventSetter Event="PreviewMouseLeftButtonDown" Handler="ListViewItem_PreviewMouseLeftButtonDown" />
</Style>
<Style x:Key="LastItemStyle" TargetType="ListViewItem" BasedOn="{StaticResource AllItemStyle}">
    <Setter Property="Border.CornerRadius" Value="0,10,10,0"/>

</Style>
<Style x:Key="FirstItemStyle" TargetType="ListViewItem" BasedOn="{StaticResource AllItemStyle}">
    <Setter Property="Border.CornerRadius" Value="10,0,0,10"/>
    <Setter Property="BorderThickness" Value="1,1,0,1"/>