WPF 自定义ListBox

发布时间 2023-06-21 16:52:46作者: 盛沧海

需求:ListBox只在选中时有相应的高亮颜色,光标悬浮或滑动时不显示高亮;以满足在触屏上时不会误导人操作……

 

以下为实现代码:

namespace FrameControlLibrary
{
    /// <summary>
    /// 按照步骤 1a 或 1b 操作,然后执行步骤 2 以在 XAML 文件中使用此自定义控件。
    ///
    /// 步骤 1a) 在当前项目中存在的 XAML 文件中使用该自定义控件。
    /// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根
    /// 元素中:
    ///
    ///     xmlns:MyNamespace="clr-namespace:FrameControlLibrary"
    ///
    ///
    /// 步骤 1b) 在其他项目中存在的 XAML 文件中使用该自定义控件。
    /// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根
    /// 元素中:
    ///
    ///     xmlns:MyNamespace="clr-namespace:FrameControlLibrary;assembly=FrameControlLibrary"
    ///
    /// 您还需要添加一个从 XAML 文件所在的项目到此项目的项目引用,
    /// 并重新生成以避免编译错误:
    ///
    ///     在解决方案资源管理器中右击目标项目,然后依次单击
    ///     “添加引用”->“项目”->[浏览查找并选择此项目]
    ///
    ///
    /// 步骤 2)
    /// 继续操作并在 XAML 文件中使用控件。
    ///
    ///     <MyNamespace:JListBox/>
    ///
    /// </summary>
    public class JListBox : ListBox
    {
        /*        static JListBox()
                {
                    DefaultStyleKeyProperty.OverrideMetadata(typeof(JListBox), new FrameworkPropertyMetadata(typeof(JListBox)));
                }*/
        public JListBox()
        {
            this.Background = Brushes.Transparent;          
            this.Loaded += JListBox_Loaded;
            //this.SelectionChanged += JListBox_SelectionChanged;
        }

        private void JListBox_Loaded(object sender, RoutedEventArgs e)
        {
            this.ItemContainerStyle = new CustomListBoxStyle();
        }

        private void JListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            //((ListBoxItem)this.SelectedItem).FocusVisualStyle = (Style)Application.Current.FindResource(SystemParameters.FocusVisualStyleKey);
           // Color color = (Color)ColorConverter.ConvertFromString("#BEE6FD");
            //((ListBoxItem)this.SelectedItem).Background = SystemColors.HighlightBrush;//new SolidColorBrush(color);
        }
    }

    public class CustomListBoxStyle : Style
    {
        public CustomListBoxStyle()
        {
            TargetType = typeof(ListBoxItem);

            Setter templateSetter = new Setter()
            {
                Property = ListBoxItem.TemplateProperty
            };

            ControlTemplate template = new ControlTemplate(typeof(ListBoxItem));
            FrameworkElementFactory borderFactory = new FrameworkElementFactory(typeof(Border));
            borderFactory.SetValue(Border.BackgroundProperty, new TemplateBindingExtension(ListBoxItem.BackgroundProperty));
            borderFactory.SetValue(Border.BorderThicknessProperty, new Thickness(1));

            FrameworkElementFactory contentPresenterFactory = new FrameworkElementFactory(typeof(ContentPresenter));
            contentPresenterFactory.SetValue(ContentPresenter.HorizontalAlignmentProperty, HorizontalAlignment.Center);
            contentPresenterFactory.SetValue(ContentPresenter.VerticalAlignmentProperty, VerticalAlignment.Center);

            borderFactory.AppendChild(contentPresenterFactory);
            template.VisualTree = borderFactory;

            templateSetter.Value = template;
            Setters.Add(templateSetter);

            //选中颜色
            Setter backgroundSetter = new Setter();
            backgroundSetter.Property = ListBoxItem.BackgroundProperty;
            backgroundSetter.Value = Brushes.Transparent;

            DataTrigger selectedTrigger = new DataTrigger();
            selectedTrigger.Binding = new Binding("IsSelected") { RelativeSource = new RelativeSource(RelativeSourceMode.Self) };
            selectedTrigger.Value = true;
            selectedTrigger.Setters.Add(new Setter(ListBoxItem.BackgroundProperty, new SolidColorBrush(Color.FromArgb(0xFF, 0xBE, 0xE6, 0xFD))));

            Triggers.Add(selectedTrigger);
            Setters.Add(backgroundSetter);

        }
    }


}

注:开始时实现选中item背景色改变是利用的SelectionChanged事件来改变,但是改变后会造成这个item的背景总是高亮,即取消选中后它还是高亮。于是后续将xaml中实现选中高亮的代码改为了后台代码,以实现这一目的。后续有更好办法,再次改进……

 

以下为在page或window中实现listbox仅选中item高亮的代码:

        <Style TargetType="{x:Type ListBoxItem}">
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListBoxItem}">
                        <Border Background="{TemplateBinding Background}"
                                BorderThickness="1">
                            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <!--<Trigger Property="IsSelected" Value="True">
                    <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightColor}}"/>
                </Trigger>-->
                <DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource Self}}" Value="true">
                    <Setter Property="Background" Value="#BEE6FD"/>
                </DataTrigger>

            </Style.Triggers>
        </Style>