zoukankan      html  css  js  c++  java
  • 多选ComboBox

    xaml

    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                        xmlns:local="clr-namespace:WessonControl.Themes" 
                        xmlns:control="clr-namespace:WessonControl.Controls">
    <Style x:Key="DefaultCheckListItem" TargetType="{x:Type control:CheckListItem}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type control:CheckListItem}">
                    <Border Background="{TemplateBinding Background}" 
                            BorderBrush="{TemplateBinding BorderBrush}" 
                            BorderThickness="{TemplateBinding BorderThickness}">
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="auto"/>
                                <ColumnDefinition/>
                            </Grid.ColumnDefinitions>
                            <CheckBox Margin="2,1,1,1"  IsChecked="{Binding IsChecked, RelativeSource={RelativeSource TemplatedParent}}"/>
                            <ContentPresenter Grid.Column="1"  Content="{TemplateBinding Content}"
                                HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style TargetType="{x:Type control:CheckList}" BasedOn="{StaticResource {x:Type ListBox}}">
        <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
        <Setter Property="ItemContainerStyle" Value="{StaticResource DefaultCheckListItem}"/>
    </Style>
    
    <ControlTemplate x:Key="ComboBoxToggleButton" TargetType="{x:Type ToggleButton}">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition Width="20" />
            </Grid.ColumnDefinitions>
            <Border x:Name="Border" Grid.ColumnSpan="2" CornerRadius="2" BorderThickness="1" BorderBrush="#FFCCCCCC">
            </Border>
            <Border Grid.Column="0" CornerRadius="2,0,0,2" Margin="1">
                <Border.Background>
                    <SolidColorBrush Color="White"/>
                </Border.Background>
            </Border>
            <Border Grid.Column="1" x:Name="Bg">
    
            </Border>
            <Path Grid.Column="1" x:Name="Arrow" HorizontalAlignment="Center" VerticalAlignment="Center" Data="M 0 0 L 4 4 L 8 0 Z">
                <Path.Fill>
                    <SolidColorBrush Color="#FF444444"/>
                </Path.Fill>
            </Path>
        </Grid>
        <ControlTemplate.Triggers>
            <Trigger Property="IsMouseOver" Value="True">
                <Setter Property="Background" TargetName="Bg" Value="#FFB9B9B9"/>
                <Setter Property="Opacity" TargetName="Bg" Value="0.6"/>
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>
    
    <!--编辑状态文本框样式-->
    <Style TargetType="{x:Type TextBox}" x:Key="EditableTextBoxStyle">
        <Setter Property="Margin" Value="1"/>
        <Setter Property="Padding" Value="0"/>
        <Setter Property="BorderThickness" Value="0"/>
        <Setter Property="Background" Value="{x:Null}"/>
        <Setter Property="MaxLength" Value="2048"/>
        <Setter Property="ContextMenu" Value="{DynamicResource TextBoxContextMenu}" />
        <Setter Property="Focusable" Value="True"/>
        <Setter Property="VerticalAlignment" Value="Center" />
        <Setter Property="HorizontalAlignment" Value="Left" />
        <Setter Property="SnapsToDevicePixels" Value="True"></Setter>
        <Style.Triggers>
        </Style.Triggers>
    </Style>
    
    <Style x:Key="DefaultMultiComboBox" TargetType="{x:Type ComboBox}">
        <Setter Property="IsEditable" Value="True"/>
        <Setter Property="IsReadOnly" Value="True" />
        <Setter Property="MinHeight" Value="26" />
        <Setter Property="SnapsToDevicePixels" Value="True" />
        <Setter Property="OverridesDefaultStyle" Value="True" />
        <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto" />
        <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
        <Setter Property="ScrollViewer.CanContentScroll" Value="True" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ComboBox}">
                    <Grid>
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal" />
                                <VisualState x:Name="MouseOver" />
                                <VisualState x:Name="Disabled">
                                </VisualState>
                            </VisualStateGroup>
                            <VisualStateGroup x:Name="EditStates">
                                <VisualState x:Name="Editable">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)"
                                                 Storyboard.TargetName="PART_EditableTextBox">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)"
                                                 Storyboard.TargetName="ContentSite">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Hidden}" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Uneditable" />
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <ToggleButton x:Name="ToggleButton" Template="{StaticResource ComboBoxToggleButton}"
                            Grid.Column="2" Focusable="false" ClickMode="Press"
                            IsChecked="{Binding IsDropDownOpen, Mode=TwoWay,  RelativeSource={RelativeSource TemplatedParent}}"/>
                        <ContentPresenter x:Name="ContentSite"
                            IsHitTestVisible="False" Margin="3,3,23,3" VerticalAlignment="Stretch" HorizontalAlignment="Left"
                            Content="{TemplateBinding SelectionBoxItem}"
                            ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
                            ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" >
                        </ContentPresenter>
                        <Grid Grid.Column="1"  Margin="2 0 0 0">
                            <TextBox x:Name="PART_EditableTextBox" Style="{StaticResource EditableTextBoxStyle}"
                                     Margin="3,3,23,3" Background="Transparent" Visibility="Hidden" IsReadOnly="{TemplateBinding IsReadOnly}"     
                                     Text="{Binding Path=SelectedText, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" />
                        </Grid>
                        <!--弹出多选列表-->
                        <Popup x:Name="Popup" Placement="Bottom" IsOpen="{TemplateBinding IsDropDownOpen}"
                             AllowsTransparency="True" Focusable="False" PopupAnimation="Slide">
                            <Grid x:Name="DropDown" SnapsToDevicePixels="True"
                                  MaxHeight="{TemplateBinding MaxDropDownHeight}"
                                  Width="{TemplateBinding ActualWidth}">
                                <control:CheckList x:Name="PART_ComboBoxItemListBox" ItemsSource="{TemplateBinding ItemsSource}"
                                                 SplitChar=";">
                                </control:CheckList>
                            </Grid>
                        </Popup>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style TargetType="{x:Type control:MultiCheckComboBox}" BasedOn="{StaticResource DefaultMultiComboBox}"/>
    </ResourceDictionary>
    

    cs

    [TemplatePart(Name = PART_ComboBoxItemListBox, Type = typeof(CheckList))]
    public partial class MultiCheckComboBox : ComboBox
    {
        // 控件模板和样式要加在资源字典中以便引用
        public const string PART_ComboBoxItemListBox = "PART_ComboBoxItemListBox";
        private CheckList _listbox;
        static MultiCheckComboBox()
        {
            // 设置样式键值
            DefaultStyleKeyProperty.OverrideMetadata(typeof(MultiCheckComboBox), new FrameworkPropertyMetadata(typeof(MultiCheckComboBox)));
        }
        public MultiCheckComboBox() { }
    
        #region SelectedText
        /// <summary>
        /// 显示内容
        /// </summary>
        public string SelectedText
        {
            get { return (string)GetValue(SelectedTextProperty); }
            set { SetValue(SelectedTextProperty, value); }
        }
        public static readonly DependencyProperty SelectedTextProperty =
            DependencyProperty.Register("SelectedText", typeof(string), typeof(MultiCheckComboBox),
                new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(OnSelectedTextPropertyChanged)));
    
        private static void OnSelectedTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is MultiCheckComboBox obj)
            {
                obj.OnSelectedTextChanged((string)e.NewValue);
            }
        }
    
        private void OnSelectedTextChanged(string displayTxt)
        {
            SetText(displayTxt);
            SelectedArrayText = null;
            SelectedArrayText = ToArray().ToList();
        }
        #endregion
        /// <summary>
        /// 显示内容的数组形式
        /// </summary>
        public IEnumerable<string> SelectedArrayText
        {
            get { return (IEnumerable<string>)GetValue(SelectedArrayTextProperty); }
            set { SetValue(SelectedArrayTextProperty, value); }
        }
        public static readonly DependencyProperty SelectedArrayTextProperty =
            DependencyProperty.Register("SelectedArrayText", typeof(IEnumerable<string>), typeof(MultiCheckComboBox), new PropertyMetadata(null));
    
    
        /// <summary>
        /// 显示的时候会执行,多用于复杂的控件。
        /// 一般在Style中使用TemplateBinding即可。
        /// 有可能出现 属性更改通知 早于 OnApplyTemplate执行的问题
        /// </summary>
        public override void OnApplyTemplate()
        {
            // 获取Style中的控件
            _listbox = GetTemplateChild(PART_ComboBoxItemListBox) as CheckList;
            if (_listbox == null)
            {
                _listbox = new CheckList();
                AddChild(_listbox);
            }
            if (_listbox != null)
            {
                _listbox.SelectedTextChanged -= Listbox_SelectedTextChanged;
                _listbox.SelectedTextChanged += Listbox_SelectedTextChanged;
            }
            base.OnApplyTemplate();
        }
    
        private void Listbox_SelectedTextChanged(object sender, RoutedEventArgs e)
        {
            SelectedText = e.OriginalSource.ToString();
        }
    
        /// <summary>
        /// 多个字符串组形式
        /// </summary>
        /// <returns></returns>
        public string[] ToArray()
        {
            if (_listbox == null || string.IsNullOrWhiteSpace(_listbox.SelectedText))
            {
                return new string[] { };
            }
            return _listbox.SelectedText.Split(_listbox.SplitChar);
        }
        /// <summary>
        /// 设置显示内容
        /// </summary>
        /// <param name="displayTxt">文本形式</param>
        public void SetText(string displayTxt)
        {
            _listbox?.SetSelectedText(displayTxt);
        }
        /// <summary>
        /// 设置显示内容
        /// </summary>
        /// <param name="item">显示项</param>
        public void SetText(CheckListItem item)
        {
            _listbox.SetSelectedItem(item);
        }
    }
    
    public class CheckListItem : ListBoxItem
    {
        static CheckListItem()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(CheckListItem), new FrameworkPropertyMetadata(typeof(CheckListItem)));
        }
    
    
        public bool IsChecked
        {
            get { return (bool)GetValue(IsCheckedProperty); }
            set { SetValue(IsCheckedProperty, value); }
        }
        public static readonly DependencyProperty IsCheckedProperty =
            DependencyProperty.Register("IsChecked", typeof(bool), typeof(CheckListItem), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(OnChanged)));
    
        public static readonly RoutedEvent CheckedChangedEvent = EventManager.RegisterRoutedEvent("CheckedChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(CheckListItem));
        public event RoutedEventHandler CheckedChanged
        {
            add
            {
                AddHandler(CheckedChangedEvent, value);
            }
            remove
            {
                RemoveHandler(CheckedChangedEvent, value);
            }
        }
    
        private static void OnChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is CheckListItem obj)
            {
                obj.OnCheckedChanged();
            }
        }
    
        public void OnCheckedChanged()
        {
            var args = new RoutedEventArgs(CheckedChangedEvent, this);
            RaiseEvent(args);
        }
    }
    
    public class CheckList : ListBox
    {
        static CheckList()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(CheckList), new FrameworkPropertyMetadata(typeof(CheckList)));
        }
    
        #region SelectedText
        /// <summary>
        /// 已选择的内容
        /// </summary>
        public string SelectedText
        {
            get { return (string)GetValue(SelectedTextProperty); }
            set { SetValue(SelectedTextProperty, value); }
        }
        public static readonly DependencyProperty SelectedTextProperty =
            DependencyProperty.Register("SelectedText", typeof(string), typeof(CheckList),
                new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(OnSelectedTextPropertyChanged)));
    
        private static void OnSelectedTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is CheckList obj)
            {
                obj.OnSelectedTextChanged(e.NewValue.ToString());
            }
        }
    
        private void OnSelectedTextChanged(string text)
        {
            var args = new RoutedEventArgs(SelectedTextChangedEvent, text);
            RaiseEvent(args);
        }
    
        public static readonly RoutedEvent SelectedTextChangedEvent = EventManager.RegisterRoutedEvent("SelectedTextChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(CheckList));
        public event RoutedEventHandler SelectedTextChanged
        {
            add { AddHandler(SelectedTextChangedEvent, value); }
            remove { RemoveHandler(SelectedTextChangedEvent, value); }
        }
    
        #endregion
    
        #region SplitChar
        /// <summary>
        /// 分隔符
        /// </summary>
        public char SplitChar
        {
            get { return (char)GetValue(SplitCharProperty); }
            set { SetValue(SplitCharProperty, value); }
        }
        public static readonly DependencyProperty SplitCharProperty =
            DependencyProperty.Register("SplitChar", typeof(char), typeof(CheckList), new PropertyMetadata(' '));
    
        #endregion
    
        protected override DependencyObject GetContainerForItemOverride()
        {
            return new CheckListItem();
        }
        protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
        {
            (element as CheckListItem).CheckedChanged += CheckList_CheckedChanged;
            base.PrepareContainerForItemOverride(element, item);
        }
    
        private void CheckList_CheckedChanged(object sender, RoutedEventArgs e)
        {
            var item = sender as CheckListItem;
            bool isChecked = item.IsChecked;
            string selected = item.Content.ToString();
            string temp = SelectedText;
            if (isChecked)
            {
                if (!Regex.IsMatch(SplitChar + SelectedText + SplitChar, SplitChar + selected + SplitChar))
                {
                    temp += SplitChar + selected;
                }
            }
            else
            {
                temp = Regex.Replace(SplitChar + temp + SplitChar, SplitChar + selected + SplitChar, SplitChar.ToString());
            }
            SelectedText = temp.Trim(SplitChar);
        }
    
        internal void SetSelectedText(string displayTxt)
        {
            if (ItemsSource == null)
            {
                return;
            }
            // 确保显示的文本是合法的
            List<string> rslt = new List<string>();
            var arr = displayTxt.Split(SplitChar);
            var list = ItemsSource.OfType<CheckListItem>();
            foreach (var item in list)
            {
                if (arr.Contains(item.Content.ToString()))
                {
                    item.IsChecked = true;
                    rslt.Add(item.Content.ToString());
                }
            }
            SelectedText = string.Join(SplitChar.ToString(), rslt.ToArray());
        }
    
        internal void SetSelectedItem(CheckListItem selectedItem)
        {
            var list = this.ItemsSource.OfType<CheckListItem>();
            foreach (var item in list)
            {
                if (item.Content.Equals(selectedItem.Content))
                {
                    item.IsChecked = true;
                    SelectedText = selectedItem.Content.ToString();
                    break;
                }
            }
        }
    }
    
    

    demo

    <wesson:MultiCheckComboBox x:Name="cmb" />
    
    var data = from p in data
                select new CheckListItem
                {
                    IsChecked = true,
                    Content = p,
                };
    cmbExtend.ItemsSource = data;
    cmbExtend.SetText(displayText);
    

    prism

    <wesson:MultiCheckComboBox x:Name="MultiCheckComboBoxSpaceType" Margin="5" Height="26"
                             ItemsSource="{Binding PropSetEntity.SpaceTypeSource}"
                             SelectedText="{Binding PropSetEntity.SpaceTypeText}"
                             SelectedArrayText="{Binding PropSetEntity.SelectedArrayText, Mode=TwoWay}">
    </wesson:MultiCheckComboBox>
    

    可多选ComboBox的简易实现
    WPF中实现多选ComboBox控件
    WPF 自定义ComboBox样式,自定义多选控件
    WPF自定义控件与样式(8)-ComboBox与自定义多选控件MultComboBox

  • 相关阅读:
    土豆案例(display:none和block的应用)
    显示和隐藏
    鼠标经过提高层级案例(margin,相对定位,z-index)
    垂直对齐vertical-align
    表单初始化
    使用定位隐式转换为行内块元素
    清除浮动的方法
    定位的盒子叠放顺序z-index
    FreeRTOS-为什么关中断之后切换进程?
    PowerPC-关闭中断后,还能报sc中断?
  • 原文地址:https://www.cnblogs.com/wesson2019-blog/p/14755186.html
Copyright © 2011-2022 走看看