【问题标题】:How do I style my ListViewItems to not have rounded corners and also have it so that selected items have their background colors inverted?如何设置我的 ListViewItems 的样式,使其不具有圆角,并让所选项目的背景颜色反转?
【发布时间】:2013-07-11 17:49:44
【问题描述】:

假设我有以下代码(您可以创建一个新的 WPF 项目并对其进行测试,只需将默认 Grid 命名为 MainGrid):

namespace WPFTesting
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        ObservableCollection<Message> messages = new ObservableCollection<Message>();

        public MainWindow()
        {
            InitializeComponent();
            messages.Add(new Message(DateTime.Now, "This is a test."));
            messages.Add(new Message(DateTime.Now, "This is a multi-line message.\nThis is a multi-line message."));
            messages.Add(new Message(DateTime.Now, "This is a multi-line message.\nThis is a multi-line message."));
            messages.Add(new Message(DateTime.Now, "This is a multi-line message.\nThis is a multi-line message."));
            messages.Add(new Message(DateTime.Now, "This is a test."));
            messages.Add(new Message(DateTime.Now, "This is a test."));
            messages.Add(new Message(DateTime.Now, "This is a test."));
            messages.Add(new Message(DateTime.Now, "This is a test."));
            ListView listView = new ListView();
            Style style = new Style();
            style.TargetType = typeof(ListViewItem);
            DataTrigger trigger = new DataTrigger();
            trigger.Binding = new Binding("Text");
            trigger.Value = "This is a test.";
            trigger.Setters.Add(new Setter(ListViewItem.BackgroundProperty, Brushes.Pink));
            style.Triggers.Add(trigger);
            style.Setters.Add(new Setter(ListViewItem.HeightProperty, 20.0));
            style.Setters.Add(new Setter(ListViewItem.MarginProperty, new Thickness(0)));
            style.Setters.Add(new Setter(ListViewItem.BorderThicknessProperty, new Thickness(0)));
            listView.ItemContainerStyle = style;
            GridView gridView = new GridView();
            listView.View = gridView;
            GridViewColumn timeStampColumn = new GridViewColumn();
            timeStampColumn.DisplayMemberBinding = new Binding("Date");
            GridViewColumnHeader timeStampHeader = new GridViewColumnHeader();
            timeStampHeader.Content = "Time";
            timeStampColumn.Header = timeStampHeader;
            gridView.Columns.Add(timeStampColumn);
            GridViewColumn messageColumn = CreateGridViewColumn("Message", "Text");
            gridView.Columns.Add(messageColumn);
            Binding binding = new Binding();
            binding.Source = messages;
            listView.SetBinding(ItemsControl.ItemsSourceProperty, binding);
            MainGrid.Children.Add(listView);
        }

        private static GridViewColumn CreateGridViewColumn(string header, string bindingPath)
        {
            GridViewColumn gridViewColumn = new GridViewColumn();
            gridViewColumn.Header = new GridViewColumnHeader() { Content = header };
            string xaml = @"
            <DataTemplate xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""> 
              <StackPanel Orientation=""Horizontal"">
                <TextBlock Text=""{Binding Text}"" MaxHeight=""20"">
                  <TextBlock.ToolTip>
                    <TextBlock Text=""{Binding Text}""/>
                  </TextBlock.ToolTip>
                </TextBlock>
              </StackPanel>
            </DataTemplate>";
            StringReader stringReader = new StringReader(xaml);
            XmlReader xmlReader = XmlReader.Create(stringReader);
            gridViewColumn.CellTemplate = XamlReader.Load(xmlReader) as DataTemplate;

            return gridViewColumn;
        }

        public class Message
        {

            public Message(DateTime aDate, String aText)
            {
                Date = aDate;
                Text = aText;
            }

            public DateTime Date { get; set; }
            public String Text { get; set; }
        }
    }
}

注意粉色线之间,ListViewItems 有轻微的圆角。如何消除这种影响?

此外,行选择并不是那么明显,因为我删除了边框厚度。如何使行选择更明显?我正在考虑反转背景颜色,但这可能不是一个好主意,或者可能添加一个具有一定透明度的画笔?我不完全确定该怎么做,有人可以告诉我吗?

【问题讨论】:

  • 一个无关紧要的问题:为什么要使用代码隐藏将样式应用于控件?这正是创建 XAML 的原因。
  • 没问题。我使用的第三方控件需要我动态添加元素,所以我不能标记它们,否则,相信我,我会的!我的例子是最简单的情况;这是一个更大的解决方案的一部分。 :P

标签: c# wpf listview gridview styling


【解决方案1】:

您可以通过为ListViewItem 创建一个新的ControlTemplate 来覆盖该Style。这是很多工作,因为它需要您重新定义所有 VisualStatesTriggers 等。

我已经包含了足够的代码来演示后面代码中的过程,这将删除圆角边框。如果你想走这条路,我会留给你添加VisualStates

 public MainWindow()
    {
        InitializeComponent();
        messages.Add(new Message(DateTime.Now, "This is a test."));
        messages.Add(new Message(DateTime.Now, "This is a multi-line message.\nThis is a multi-line message."));
        messages.Add(new Message(DateTime.Now, "This is a multi-line message.\nThis is a multi-line message."));
        messages.Add(new Message(DateTime.Now, "This is a multi-line message.\nThis is a multi-line message."));
        messages.Add(new Message(DateTime.Now, "This is a test."));
        messages.Add(new Message(DateTime.Now, "This is a test."));
        messages.Add(new Message(DateTime.Now, "This is a test."));
        messages.Add(new Message(DateTime.Now, "This is a test."));
        ListView listView = new ListView();
        CreateListViewItemStyle(listView);
        GridView gridView = new GridView();
        listView.View = gridView;
        GridViewColumn timeStampColumn = new GridViewColumn();
        timeStampColumn.DisplayMemberBinding = new Binding("Date");
        GridViewColumnHeader timeStampHeader = new GridViewColumnHeader();
        timeStampHeader.Content = "Time";
        timeStampColumn.Header = timeStampHeader;
        gridView.Columns.Add(timeStampColumn);
        GridViewColumn messageColumn = CreateGridViewColumn("Message", "Text");
        gridView.Columns.Add(messageColumn);
        Binding binding = new Binding();
        binding.Source = messages;
        listView.SetBinding(ItemsControl.ItemsSourceProperty, binding);
        MainGrid.Children.Add(listView);
    }

    private static void CreateListViewItemStyle(ListView listView)
    {
        string xaml = @"
        <Style  xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"" TargetType=""ListViewItem"">
            <Setter Property=""Height"" Value=""20""/>
            <Setter Property=""Template"">
                <Setter.Value>
                <ControlTemplate TargetType=""{x:Type ListViewItem}"">
                    <Border Background=""{TemplateBinding Background}""
                            CornerRadius=""0"">
                        <GridViewRowPresenter/>
                    </Border>
                </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <DataTrigger Binding=""{Binding Text}"" Value=""This is a test."">
                    <Setter Property=""Background"" Value=""Pink""/>
                </DataTrigger>
            </Style.Triggers>
        </Style>";
        StringReader stringReader = new StringReader(xaml);
        XmlReader xmlReader = XmlReader.Create(stringReader);
        listView.ItemContainerStyle = XamlReader.Load(xmlReader) as Style;
    }

【讨论】:

  • 这正是我要找的!问你一个问题,你怎么知道你必须将 CornerRadius 设置为 0?您是否从 Microsoft 框架应用的默认样式中获得了 ControlTemplate?
  • 当您定义一个 ControlTemplate 时,您实际上是从头开始设置控件的样式(因此所有的 VisualStates 都不再起作用)。您实际上可以删除 'CornerRadius="0"' 行,它仍然可以工作。我只是为了清楚起见才添加它,因为这是导致默认模板中舍入的属性。
【解决方案2】:

尝试查看以下 XAML 编码。使用 Datagrid 代替 ListView。

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Window.Resources>
    <Style TargetType="{x:Type DataGridRow}">
        <Style.Triggers>
            <Trigger Property="IsMouseOver"
                     Value="True">
                <Setter Property="Background"
                        Value="Red" />
                <Setter Property="FontWeight"
                        Value="ExtraBold" />
                <Setter Property="Height"
                        Value="20" />
            </Trigger>
            <DataTrigger Binding="{Binding Text}" Value="This is a test.">
                <Setter Property="Background" Value="Pink" />
            </DataTrigger>
        </Style.Triggers>
    </Style>
</Window.Resources>
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <Grid x:Name="MainGrid" />

    <DataGrid Margin="10" Grid.Row="1" x:Name="MainGrid1"
          AutoGenerateColumns="False"
          AlternationCount="2"
          FrozenColumnCount="2">
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding Date}"
                            Header="Time" Width="Auto" />
            <DataGridTextColumn Binding="{Binding Text}"
                            Header="Message" Width="*" />
        </DataGrid.Columns>
    </DataGrid>
</Grid>

在MainWindow的构造函数末尾,添加以下最后一行

        Binding binding = new Binding();
        binding.Source = messages;
        listView.SetBinding(ItemsControl.ItemsSourceProperty, binding);
        MainGrid.Children.Add(listView);

        MainGrid1.ItemsSource = messages;

您可能需要编写多重触发器来检查文本值和鼠标悬停,然后更改适当的背景颜色。

【讨论】:

  • 这可行,而且您的解决方案很棒。我非常感谢您在这里所做的工作,但遗憾的是,我必须使用 ListView,因为所有的开发工作都已经使用这个对象完成了,现在切换到 DataGrid 为时已晚。有没有办法设置 ListView 的样式并让它工作?一定有办法的。
【解决方案3】:

直接将您的样式应用到 ListView 时,它似乎可以按您的意愿工作。我相信圆形样式是由您用作 ListView 视图的 GridView 强加给项目的。

如果可能,我建议考虑使用不同的控件集合来显示您的项目。

【讨论】:

  • 一定有办法覆盖那种风格。
猜你喜欢
  • 2017-01-09
  • 2016-07-26
  • 2020-11-30
  • 1970-01-01
  • 2013-08-25
  • 1970-01-01
  • 2021-04-26
  • 2023-03-24
  • 1970-01-01
相关资源
最近更新 更多