zoukankan      html  css  js  c++  java
  • WPF 自定义ComboBox样式,自定义多选控件

    引用网址:https://www.cnblogs.com/xiaomingg/p/8748286.html

    一、ComboBox基本样式

    ComboBox有两种状态,可编辑和不可编辑状态。通过设置IsEditable属性可以切换控件状态。

    先看基本样式效果:

    基本样式代码如下:

    复制代码
    <!--ComboBox-->
            <!--ComBoBox项选中背景色-->
            <SolidColorBrush x:Key="ComboBoxSelectdBackground" Color="#ff8c69"/>
            <!--ComBoBox项鼠标经过背景色-->
            <SolidColorBrush x:Key="ComboBoxMouseOverBackground" Color="#ff3030"/>
            <!--ComBoBox项选中前景色-->
            <SolidColorBrush x:Key="ComboBoxSelectedForeground" Color="White"/>
            <!--ComBoBox项鼠标经过前景色-->
            <SolidColorBrush x:Key="ComboBoxMouseOverForegrond" Color="White"/>
            <Style TargetType="{x:Type ComboBox}">
                <Setter Property="ItemContainerStyle">
                    <Setter.Value>
                        <Style TargetType="ComboBoxItem">
                            <Setter Property="Height" Value="20"/>
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate  TargetType="{x:Type ComboBoxItem}">
                                        <Grid Height="{TemplateBinding Height}" Width="{TemplateBinding Width}">
                                            <Border x:Name="_borderbg" Background="Transparent"/>
                                            <TextBlock Margin="3 0 3 0" VerticalAlignment="Center" x:Name="_txt" Foreground="#333" Text="{Binding Content,RelativeSource={RelativeSource TemplatedParent}}"/>
                                            <Border x:Name="_border" Background="White" Opacity="0"/>
                                        </Grid>
                                        <ControlTemplate.Triggers>
                                            <Trigger Property="IsSelected" Value="true">
                                                <Setter TargetName="_borderbg" Property="Background" Value="{StaticResource ComboBoxSelectdBackground}" />
                                                <Setter TargetName="_txt" Property="Foreground" Value="{StaticResource ComboBoxSelectedForeground}"/>
                                            </Trigger>
                                            <MultiTrigger>
                                                <MultiTrigger.Conditions>
                                                    <Condition Property="IsSelected" Value="false"/>
                                                    <Condition Property="IsMouseOver" Value="true"/>
                                                </MultiTrigger.Conditions>
                                                <Setter TargetName="_borderbg" Property="Background" Value="{StaticResource ComboBoxMouseOverBackground}" />
                                                <Setter TargetName="_txt" Property="Foreground" Value="{StaticResource ComboBoxMouseOverForegrond}"/>
                                            </MultiTrigger>
    
                                        </ControlTemplate.Triggers>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </Setter.Value>
                </Setter>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ComboBox}">
                            <Grid>
    
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="0.7*"/>
                                    <ColumnDefinition Width="0.3*" MaxWidth="30"/>
                                </Grid.ColumnDefinitions>
                                <Border  Grid.Column="0" Grid.ColumnSpan="2" BorderThickness="1" BorderBrush="{TemplateBinding BorderBrush}" CornerRadius="1,0,0,1"/>
                                <ContentPresenter HorizontalAlignment="Left" Margin="3,3,0,3" x:Name="ContentSite" VerticalAlignment="Center" Content="{TemplateBinding SelectionBoxItem}" ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" IsHitTestVisible="False"/>
    
                                <!--ToggleButton 已数据绑定到 ComboBox 本身以切换 IsDropDownOpen-->
                                <ToggleButton Grid.Column="0"  Grid.ColumnSpan="2"  Template="{StaticResource ComboBoxToggleButton}" x:Name="ToggleButton" Focusable="false" IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press"/>
                                <!--必须将 TextBox 命名为 PART_EditableTextBox,否则 ComboBox 将无法识别它-->
                                <TextBox   Visibility="Hidden" BorderThickness="0"   Margin="2 0 0 0" x:Name="PART_EditableTextBox"  VerticalAlignment="Center" Focusable="True" Background="Transparent" IsReadOnly="{TemplateBinding IsReadOnly}"/>
    
                                <!--Popup 可显示 ComboBox 中的项列表。IsOpen 已数据绑定到通过 ComboBoxToggleButton 来切换的 IsDropDownOpen-->
                                <Popup IsOpen="{TemplateBinding IsDropDownOpen}" Placement="Bottom" x:Name="Popup" Focusable="False" AllowsTransparency="True" PopupAnimation="Slide">
                                    <Grid MaxHeight="150" MinWidth="{TemplateBinding ActualWidth}" x:Name="DropDown" SnapsToDevicePixels="True">
                                        <Border x:Name="DropDownBorder"  BorderBrush="#e8e8e8" BorderThickness="1 0 1 1"/>
                                        <ScrollViewer Margin="1"  SnapsToDevicePixels="True" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" CanContentScroll="True">
                                            <!--StackPanel 用于显示子级,方法是将 IsItemsHost 设置为 True-->
                                            <StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" Background="White"/>
                                        </ScrollViewer>
                                    </Grid>
                                </Popup>
                            </Grid>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsEditable" Value="true">
                                    <Setter TargetName="PART_EditableTextBox" Property="Visibility" Value="Visible" />
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
    复制代码

    引用示例:

    复制代码
     <ComboBox x:Name="combobox"  Width="150" Margin="10" IsEditable="False" BorderBrush="#e8e8e8">
              <CheckBox Content="上海" Tag="1"></CheckBox>
              <CheckBox Content="北京" Tag="2"></CheckBox>
              <CheckBox Content="天津" Tag="3"></CheckBox>
              <CheckBox Content="广州" Tag="4"></CheckBox>
    </ComboBox>
    复制代码

    二、ComboBox扩展样式(多选控件)

    ComBoBox能够单选选择数据,那么能不能实现多选的操作呢,答案是肯定的。这里多选的自定义控件参考了博主“梦里花落知多少”的内容。我对样式做了补充,使其能够更方便的进行移除多选的内容。同时也更好的展示了已选的内容,大家可以根据实际需求做出更好的展示效果。

    先看效果:

    2.1、添加自定义控件MultiComboBox

    复制代码
     public class MultiComboBox : ComboBox
        {
            static MultiComboBox()
            {
                DefaultStyleKeyProperty.OverrideMetadata(typeof(MultiComboBox), new FrameworkPropertyMetadata(typeof(MultiComboBox)));
            }
    
    
            private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                d.SetValue(e.Property, e.NewValue);
            }
    
    
    
            /// <summary>
            /// 选中项列表
            /// </summary>
            public ObservableCollection<MultiCbxBaseData> ChekedItems
            {
                get { return (ObservableCollection<MultiCbxBaseData>)GetValue(ChekedItemsProperty); }
                set { SetValue(ChekedItemsProperty, value); }
            }
    
            public static readonly DependencyProperty ChekedItemsProperty =
                DependencyProperty.Register("ChekedItems", typeof(ObservableCollection<MultiCbxBaseData>), typeof(MultiComboBox), new PropertyMetadata(new ObservableCollection<MultiCbxBaseData>(), OnPropertyChanged));
    
    
    
            /// <summary>
            /// ListBox竖向列表
            /// </summary>
            private ListBox _ListBoxV;
    
            /// <summary>
            /// ListBox横向列表
            /// </summary>
            private ListBox _ListBoxH;
    
            public override void OnApplyTemplate()
            {
                base.OnApplyTemplate();
                _ListBoxV = Template.FindName("PART_ListBox", this) as ListBox;
                _ListBoxH = Template.FindName("PART_ListBoxChk", this) as ListBox;
                _ListBoxH.ItemsSource = ChekedItems;
                _ListBoxV.SelectionChanged += _ListBoxV_SelectionChanged;
                _ListBoxH.SelectionChanged += _ListBoxH_SelectionChanged;
    
                if (ItemsSource != null)
                {
                    foreach (var item in ItemsSource)
                    {
                        MultiCbxBaseData bdc = item as MultiCbxBaseData;
                        if (bdc.IsCheck)
                        {
                            _ListBoxV.SelectedItems.Add(bdc);
                        }
                    }
                }
            }
    
            private void _ListBoxH_SelectionChanged(object sender, SelectionChangedEventArgs e)
            {
                foreach (var item in e.RemovedItems)
                {
                    MultiCbxBaseData datachk = item as MultiCbxBaseData;
    
                    for (int i = 0; i < _ListBoxV.SelectedItems.Count; i++)
                    {
                        MultiCbxBaseData datachklist = _ListBoxV.SelectedItems[i] as MultiCbxBaseData;
                        if (datachklist.ID == datachk.ID)
                        {
                            _ListBoxV.SelectedItems.Remove(_ListBoxV.SelectedItems[i]);
                        }
                    }
                }
            }
    
            void _ListBoxV_SelectionChanged(object sender, SelectionChangedEventArgs e)
            {
                foreach (var item in e.AddedItems)
                {
                    MultiCbxBaseData datachk = item as MultiCbxBaseData;
                    datachk.IsCheck = true;
                    if (ChekedItems.IndexOf(datachk) < 0)
                    {
                        ChekedItems.Add(datachk);
                    }
                }
    
                foreach (var item in e.RemovedItems)
                {
                    MultiCbxBaseData datachk = item as MultiCbxBaseData;
                    datachk.IsCheck = false;
                    ChekedItems.Remove(datachk);
                }
            }
    
            public class MultiCbxBaseData
            {
                private int _id;
                /// <summary>
                /// 关联主键
                /// </summary>
                public int ID
                {
                    get { return _id; }
                    set { _id = value; }
                }
    
                private string _viewName;
                /// <summary>
                /// 显示名称
                /// </summary>
                public string ViewName
                {
                    get { return _viewName; }
                    set
                    {
                        _viewName = value;
                    }
                }
    
                private bool _isCheck;
                /// <summary>
                /// 是否选中
                /// </summary>
                public bool IsCheck
                {
                    get { return _isCheck; }
                    set { _isCheck = value;}
                }
            }
        }
    复制代码

    2.2、定义MultiComboBox控件的样式

    复制代码
     <ControlTemplate x:Key="ComboBoxToggleButton" TargetType="{x:Type ToggleButton}">
            <Grid Height="25">
                <Border Grid.Column="1" Background="White" Opacity="0"   Cursor="Hand"/>
                <Path x:Name="Arrow" Grid.Column="1"   Data="M 0 0  6 6 12 0 Z"  VerticalAlignment="Center" HorizontalAlignment="Center" Stretch="None" Fill="#B1B1B1" />
            </Grid>
            <ControlTemplate.Triggers>
                <Trigger Property="IsChecked" Value="true">
                    <Setter TargetName="Arrow" Property="RenderTransform">
                        <Setter.Value>
                            <RotateTransform   CenterX="6" CenterY="3" Angle="180"></RotateTransform>
                        </Setter.Value>
                    </Setter>
                    <Setter TargetName="Arrow" Property="Margin" Value="0 0 0 2"/>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    
        <!--MultiComboBox普通样式-->
        <Style  TargetType="{x:Type local:MultiComboBox}">
            <Setter Property="Width" Value="200" />
            <Setter Property="HorizontalContentAlignment" Value="Stretch" />
            <Setter Property="VerticalContentAlignment" Value="Center" />
            <Setter Property="SnapsToDevicePixels" Value="True" />
            <Setter Property="MaxDropDownHeight" Value="400" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type local:MultiComboBox}">
                        <Grid>
                            <Border x:Name="Bg" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"  Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" BorderBrush="#eaeaea" BorderThickness="1"  >
                                <Grid x:Name="PART_Root">
    
                                    <Grid x:Name="PART_InnerGrid" Margin="0">
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width="*" />
                                            <ColumnDefinition Width="0.3*" MaxWidth="30" />
                                        </Grid.ColumnDefinitions>
                                        <ListBox x:Name="PART_ListBoxChk"  SelectionMode="Multiple" BorderThickness="0" ScrollViewer.VerticalScrollBarVisibility="Disabled">
                                            <ListBox.ItemsPanel>
                                                <ItemsPanelTemplate>
                                                    <VirtualizingStackPanel Orientation="Horizontal" VirtualizingStackPanel.IsVirtualizing="True" />
                                                </ItemsPanelTemplate>
                                            </ListBox.ItemsPanel>
                                            <ListBox.ItemContainerStyle>
                                                <Style TargetType="ListBoxItem">
                                                    <Setter Property="BorderThickness" Value="0"/>
                                                    <Setter Property="IsSelected" Value="True"/>
                                                    <Setter Property="Template">
                                                        <Setter.Value>
                                                            <ControlTemplate TargetType="ListBoxItem">
                                                                <CheckBox BorderThickness="0"  VerticalAlignment="Center" HorizontalAlignment="Center"  Content="{Binding ViewName}" IsChecked="{Binding Path=IsSelected,RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
                                                            </ControlTemplate>
                                                        </Setter.Value>
                                                    </Setter>
                                                </Style>
                                            </ListBox.ItemContainerStyle>
                                        </ListBox>
    
                                        <!--下拉按钮-->
                                        <ToggleButton x:Name="PART_DropDownToggle" IsTabStop="False"  
                                             IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
                                             Grid.Column="1" Template="{StaticResource ComboBoxToggleButton}" />
                                    </Grid>
                                </Grid>
                            </Border>
                            <!--弹出多选列表-->
                            <Popup x:Name="PART_Popup" AllowsTransparency="True"  Focusable="False" StaysOpen="False"
                                   IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}"
                                   PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Placement="Bottom">
                                <Grid Width="{Binding ActualWidth, RelativeSource={RelativeSource TemplatedParent}}"  MaxHeight="{Binding MaxDropDownHeight, RelativeSource={RelativeSource TemplatedParent}}" >
                                    <ListBox x:Name="PART_ListBox" SelectionMode="Multiple" BorderThickness="1 0 1 1" Background="White" ItemsSource="{Binding ItemsSource,RelativeSource={RelativeSource TemplatedParent}}"
                                                 MaxHeight="{TemplateBinding MaxDropDownHeight}" BorderBrush="#eaeaea"  >
                                        <ListBox.ItemContainerStyle>
                                            <Style  TargetType="ListBoxItem">
                                                <Setter Property="Template">
                                                    <Setter.Value>
                                                        <ControlTemplate TargetType="{x:Type ListBoxItem}" >
                                                            <Grid  Height="22">
                                                                <Border x:Name="bg" BorderBrush="#eaeaea" BorderThickness="0"/>
                                                                <ContentPresenter x:Name="content"  />
                                                                <Border Background="White"  Opacity="0"/>
                                                            </Grid>
                                                            <ControlTemplate.Triggers>
                                                                <Trigger Property="IsSelected" Value="True">
                                                                    <Setter  TargetName="bg"  Property="Background" Value="#ADD6FF" />
                                                                </Trigger>
                                                                <MultiTrigger>
                                                                    <MultiTrigger.Conditions>
                                                                        <Condition Property="IsMouseOver" Value="true" />
                                                                        <Condition Property="IsSelected" Value="false"/>
                                                                    </MultiTrigger.Conditions>
                                                                    <Setter TargetName="bg" Property="Background" Value="#009BDB" />
                                                                    <Setter TargetName="bg" Property="Opacity" Value="0.7"/>
                                                                    <Setter   Property="Foreground" Value="White" />
                                                                </MultiTrigger>
                                                                <Trigger Property="IsEnabled" Value="False">
                                                                    <Setter TargetName="bg" Property="Opacity" Value="0.3" />
                                                                    <Setter   Property="Foreground" Value="Gray" />
                                                                </Trigger>
                                                            </ControlTemplate.Triggers>
                                                        </ControlTemplate>
                                                    </Setter.Value>
                                                </Setter>
                                            </Style>
                                        </ListBox.ItemContainerStyle>
                                        <ListBox.ItemTemplate>
                                            <DataTemplate>
                                                <Grid>
                                                    <CheckBox x:Name="chk" Visibility="Hidden"  IsChecked="{Binding IsCheck,Mode=TwoWay}" VerticalAlignment="Center"/>
                                                    <CheckBox VerticalAlignment="Center"  Foreground="{Binding Foreground,RelativeSource={RelativeSource AncestorType=ListBoxItem}}" IsChecked="{Binding  RelativeSource={RelativeSource AncestorType=ListBoxItem},Path=IsSelected,Mode=TwoWay}"  Content="{Binding Path=ViewName}" />
                                                </Grid>
                                                <DataTemplate.Triggers>
                                                    <DataTrigger   Binding="{Binding  RelativeSource={RelativeSource AncestorType=ListBoxItem},Path=IsSelected}" Value="true">
                                                        <Setter  TargetName="chk"  Property="IsChecked" Value="true"/>
                                                    </DataTrigger>
                                                    <DataTrigger   Binding="{Binding  RelativeSource={RelativeSource AncestorType=ListBoxItem},Path=IsSelected}" Value="false">
                                                        <Setter     TargetName="chk" Property="IsChecked" Value="false"/>
                                                    </DataTrigger>
                                                </DataTemplate.Triggers>
                                            </DataTemplate>
                                        </ListBox.ItemTemplate>
                                    </ListBox>
                                </Grid>
                            </Popup>
                        </Grid>
                        
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    复制代码

    2.3、引用示例:

    <local:MultiComboBox x:Name="multiCmb" Margin="10" Width="200"/>

    2.4、后台代码(初始化绑定数据):

    复制代码
      public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                MultiComboBoxList = new ObservableCollection<MultiCbxBaseData>()
                {
                    new MultiCbxBaseData(){
                        ID=0,
                        ViewName="张三",
                        IsCheck=false
                    },
                    new MultiCbxBaseData(){
                        ID=1,
                        ViewName="李四",
                        IsCheck=false
                    },
                    new MultiCbxBaseData(){
                        ID=2,
                        ViewName="王五",
                        IsCheck=false
                    },
                    new MultiCbxBaseData(){
                        ID=3,
                        ViewName="马六",
                        IsCheck=false
                    },
                     new MultiCbxBaseData(){
                        ID=4,
                        ViewName="赵七",
                        IsCheck=false
                    },
                };
                this.multiCmb.ItemsSource = MultiComboBoxList;
            }
    
            private ObservableCollection<MultiCbxBaseData> MultiComboBoxList;
        }
    复制代码

    所有代码已经上传到github:https://github.com/cmfGit/WpfDemo.git

    作者:一叶知秋
  • 相关阅读:
    你写的单例真的安全吗?
    CountDownLatch&&CyclicBarrier
    初步认识AQS
    Atomic底层原理
    volatile关键字
    Linux常用服务类相关命令
    线程池
    由浅入深TheradLocal
    synchronized关键字
    .net 中dapper实现事务的三种方式总结
  • 原文地址:https://www.cnblogs.com/bruce1992/p/15774855.html
Copyright © 2011-2022 走看看