【问题标题】:How can I override the ContentTemplate of a ListView to add a vertical separator?如何覆盖 ListView 的 ContentTemplate 以添加垂直分隔符?
【发布时间】:2017-08-02 13:42:01
【问题描述】:

我正在寻找修改 WPF ListView 以便水平呈现项目,并且在第一项和所有后续项目之间有一个分隔符。像这样:

我有水平位,但我被分隔符卡住了。我尝试使用 DataTemplate,但这会将分隔符合并到实际项目中,这意味着当我悬停时它会突出显示(注意我使用的是 Caliburn,但我认为它不会对问题产生太大影响):

<UserControl.Resources>
    <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</UserControl.Resources>
<StackPanel Margin="20">
    <ListView Name="Items" BorderThickness="0">
        <ListView.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <ContentControl cal:View.Model="{Binding}" />
                    <Border Name="Separator" Width="2" Margin="5,10" HorizontalAlignment="Center" Background="Red" Visibility="{Binding IsFirst, Converter={StaticResource BooleanToVisibilityConverter}}" />
                </StackPanel>
            </DataTemplate>
        </ListView.ItemTemplate>
        <ListView.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal" />
            </ItemsPanelTemplate>
        </ListView.ItemsPanel>
    </ListView>
</StackPanel>

Items 是带有此边框的非常基本的视图:

<Border Background="White" BorderBrush="Black" BorderThickness="2">

DataTemplate 的外观:

在花了一上午的时间阅读模板后,我决定使用 ControlTemplate 作为解决方案,经过一番努力,我得到了以下代码:

<UserControl.Resources>
    <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
    <Style TargetType="ListViewItem">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ListViewItem">
                    <StackPanel Margin="10" Orientation="Horizontal">
                        <ContentPresenter Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" />
                        <Border Name="Separator" Width="2" Margin="5,10" HorizontalAlignment="Center" Background="Red" Visibility="{Binding IsFirst, Converter={StaticResource BooleanToVisibilityConverter}}" />
                    </StackPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</UserControl.Resources>
<StackPanel>
    <ListView Name="Items">
        <ListView.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal" />
            </ItemsPanelTemplate>
        </ListView.ItemsPanel>
    </ListView>
</StackPanel>

这看起来几乎相同,但现在由于某种原因我无法突出显示项目。我想也许我也覆盖了触发器,并尝试根据以下答案添加 ControlTemplate.Triggers 条目:Change selection-color of WPF ListViewItem 以恢复突出显示行为,但没有成功。

我怎样才能得到我正在寻找的结果,ControlTemplate 是进行此更改的正确位置吗?

编辑:理想情况下,我正在寻找仅使用 xaml 的解决方案。

【问题讨论】:

  • 该分隔符是项目容器的一部分,而不是 ListViewItem 本身。你现在用的是水平的StackPanel,试着写自己的HorizontalPanelWithSeparator
  • 我会试试的,谢谢。

标签: c# wpf listview controltemplate


【解决方案1】:

这是一个带分隔符的自定义面板的快速尝试

public class MyPanel : StackPanel
{
    static MyPanel()
    {
        OrientationProperty.OverrideMetadata(typeof(MyPanel), new FrameworkPropertyMetadata(Orientation.Horizontal));
    }

    protected override void OnRender(DrawingContext dc)
    {
        base.OnRender(dc);
        if (Children.Count >= 2)
        {
            var child = Children[0] as FrameworkElement;
            if (child != null)
                dc.DrawLine(new Pen(Brushes.Red, 2), new Point(child.ActualWidth + 2, 5), new Point(child.ActualWidth + 2, ActualHeight - 5));
        }
    }
}

这样使用

<ListView.ItemsPanel>
    <ItemsPanelTemplate>
        <local:MyPanel/>
    </ItemsPanelTemplate>
</ListView.ItemsPanel>

当前面板不安排/测量子级为分隔符分配空间,您必须确保它们之间有一个边距。

【讨论】:

  • 谢谢你,稍微摆弄一下边距,我就能产生我想要的行为。理想情况下,我正在寻找一个仅限 xaml 的解决方案,因此我将保留问题并继续试验,但如果没有其他问题,我会接受这个。
【解决方案2】:

使用ItemTemplateSelector 来实现这一点。

如果您可以展示您的视图模型,我可以更具体地为您提供帮助。但是您的第一项数据模板将与其他项目不同,并包含您想要的分隔符。其余项目可以使用普通模板。

作为替代方法,将可见性属性数据绑定到视图模型中的布尔字段,该字段仅适用于第一项。

【讨论】:

  • 您好 Tanveer,感谢您的回答,不幸的是能见度不是我的问题。当我将鼠标悬停在第一个项目上时(如我的第二张图片所示),我正在努力让分隔符不包含在突出显示框中。至于 ViewModel,ItemViewModel 仅包含一个 boolean IsFirst 属性,ItemsViewModel 仅包含一个 List&lt;ItemViewModel&gt; 属性,我在构造函数中使用 3 个项目对其进行初始化(将 true 传递给第一个,将 false 传递给第二个)。
【解决方案3】:

我设法弄清楚如何重新添加触发器(我使用我最喜欢的新 WPF 工具 WPF Inspector 确认缺少触发器)。完成后,最后一个问题是分隔符还触发了第一个元素的鼠标悬停事件,我通过定位内边框来修复该事件:

<UserControl.Resources>
    <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
    <Style TargetType="ListViewItem">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ListViewItem">
                    <StackPanel Orientation="Horizontal">
                        <Border x:Name="ItemBorder" Padding="2">
                            <StackPanel>
                                <ContentPresenter />
                            </StackPanel>
                        </Border>
                        <Border Name="Separator" Width="2" Margin="5,10" HorizontalAlignment="Center" Background="Red" Visibility="{Binding IsFirst, Converter={StaticResource BooleanToVisibilityConverter}}" />
                    </StackPanel>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsSelected" Value="True">
                            <Setter TargetName="ItemBorder" Property="Border.Background" Value="Blue" />
                            <Setter TargetName="ItemBorder" Property="Border.BorderBrush" Value="Green" />
                        </Trigger>
                        <DataTrigger Binding="{Binding ElementName=ItemBorder, Path=IsMouseOver}" Value="True">
                            <Setter TargetName="ItemBorder" Property="Border.Background" Value="Yellow" />
                        </DataTrigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</UserControl.Resources>
<StackPanel>
    <ListView Name="Items">
        <ListView.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal" />
            </ItemsPanelTemplate>
        </ListView.ItemsPanel>
    </ListView>
</StackPanel>

由于某些未知原因,ItemBorder 元素需要填充 2,否则无法看到边框。

【讨论】:

    猜你喜欢
    • 2012-11-15
    • 1970-01-01
    • 2018-05-04
    • 2021-04-30
    • 2013-08-20
    • 2020-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多