Silverlight中实现带CheckBox的多选下拉框(源码下载)

作者:袖梨 2022-06-25

第一种格式:使用DisplayPath和SelectedValuePath,使用自定义分隔符 "|"

第二种格式:

这个版本对于我们的项目应用已经够了,但是其中还有一个问题没有解决 SelectedValue的双向绑定有些问题、从源端到控件的绑定还没有处理

好了下面我们来看代码CheckedComboBox.cs

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Controls.Primitives;
using System.Windows.Interop;
using System.Windows.Data;

namespace SL.UI.Form
{
    [TemplatePart(Name = "DropDownToggle", Type = typeof(ToggleButton)),
    TemplateVisualState(Name = "InvalidFocused", GroupName = "ValidationStates"),
    TemplatePart(Name = "ContentPresenter", Type = typeof(ContentPresenter)),
    TemplatePart(Name = "Popup", Type = typeof(Popup)),
    TemplatePart(Name = "ContentPresenterBorder", Type = typeof(FrameworkElement)),
    TemplatePart(Name = "ScrollViewer", Type = typeof(ScrollViewer)),
    TemplateVisualState(Name = "Normal", GroupName = "CommonStates"),
    TemplateVisualState(Name = "MouseOver", GroupName = "CommonStates"),
    TemplateVisualState(Name = "Disabled", GroupName = "CommonStates"),
    TemplateVisualState(Name = "Unfocused", GroupName = "FocusStates"),
    TemplateVisualState(Name = "Focused", GroupName = "FocusStates"),
    TemplateVisualState(Name = "FocusedDropDown", GroupName = "FocusStates"),
    TemplateVisualState(Name = "Valid", GroupName = "ValidationStates"),
    TemplateVisualState(Name = "InvalidUnfocused", GroupName = "ValidationStates")]
    public class CheckedComboBox : ItemsControl
    {
        private const string ElementContentPresenterBorderName = "ContentPresenterBorder";
        private const string ElementContentPresenterName = "ContentPresenter";
        private const string ElementDropDownToggleName = "DropDownToggle";
        private const string ElementPopupName = "Popup";
        private const string ElementItemsPresenterName = "ItemsPresenter";

        private ContentPresenter ElementContentPresenter;
        private FrameworkElement ElementContentPresenterBorder;
        private ListBox ElementItemsPresenter;
        private FrameworkElement ElementPopupChild;
        private ToggleButton ElementDropDownToggle;

        private Canvas ElementOutsidePopup;
        private Popup ElementPopup;
        private Canvas ElementPopupChildCanvas;
        private bool _isMouseOverMain;
        private bool _isMouseOverPopup;

        #region DependencyProperty
        public static readonly DependencyProperty IsDropDownOpenProperty;
        public bool IsDropDownOpen
        {
            get
            {
                return (bool)base.GetValue(IsDropDownOpenProperty);
            }
            set
            {
                base.SetValue(IsDropDownOpenProperty, value);
            }
        }
        public static readonly DependencyProperty MaxDropDownHeightProperty;
        public double MaxDropDownHeight
        {
            get
            {
                return (double)base.GetValue(MaxDropDownHeightProperty);
            }
            set
            {
                base.SetValue(MaxDropDownHeightProperty, value);
            }
        }
        public static readonly DependencyProperty SelectedValueProperty;
        public object SelectedValue
        {
            get { return base.GetValue(SelectedValueProperty); }
            set { base.SetValue(SelectedValueProperty, value); }
        }
        public static readonly DependencyProperty SelectedValuePathProperty;
        public string SelectedValuePath
        {
            get { return (string)base.GetValue(SelectedValuePathProperty); }
            set { base.SetValue(SelectedValuePathProperty, value); }
        }
        public static readonly DependencyProperty SeparatorCharProperty;
        public string SeparatorChar
        {
            get { return (string)base.GetValue(SeparatorCharProperty); }
            set { base.SetValue(SeparatorCharProperty, value); }
        }
        public static readonly DependencyProperty SelectionModeProperty;
        public SelectionMode SelectionMode
        {
            get { return (SelectionMode)base.GetValue(SelectionModeProperty); }
            set { base.SetValue(SelectionModeProperty, value); }
        }
        #endregion

        #region Events
        public event EventHandler DropDownClosed;
        public event EventHandler DropDownOpened;
        public event SelectionChangedEventHandler SelectionChanged;
        #endregion

        #region DependencyPropertyChangedCallback
        private static void OnIsDropDownOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            CheckedComboBox box = (CheckedComboBox)d;
            box.OnIsDropDownOpenChanged((bool)e.NewValue);
        }
        private static void OnMaxDropDownHeightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((CheckedComboBox)d).OnMaxDropDownHeightChanged((double)e.NewValue);
        }
        private static void OnSelectedValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            CheckedComboBox ccb = d as CheckedComboBox;
            if (e.NewValue != null && !e.NewValue.Equals(e.OldValue))
            { ccb.OnSelectedValueChanged(e.NewValue); }

        }
        private static void OnSelectedValuePathPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
        }
        private static void OnSeparatorCharPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {

        }
        private static void OnSelectionModePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            CheckedComboBox ccb = d as CheckedComboBox;
            if (ccb != null)
            {
                ccb.ElementItemsPresenter.SelectionMode = (SelectionMode)e.NewValue;
            }
        }
        #endregion

        static CheckedComboBox()
        {
            IsDropDownOpenProperty = DependencyProperty.Register("IsDropDownOpen", typeof(bool), typeof(CheckedComboBox), new PropertyMetadata(new PropertyChangedCallback(OnIsDropDownOpenChanged)));
            MaxDropDownHeightProperty = DependencyProperty.Register("MaxDropDownHeight", typeof(double), typeof(CheckedComboBox), new PropertyMetadata((double)1.0 / (double)0.0, new PropertyChangedCallback(OnMaxDropDownHeightChanged)));
            SelectedValueProperty = DependencyProperty.Register("SelectedValue", typeof(object), typeof(CheckedComboBox), new PropertyMetadata(null, new PropertyChangedCallback(OnSelectedValuePropertyChanged)));
            SelectedValuePathProperty = DependencyProperty.Register("SelectedValuePath", typeof(string), typeof(CheckedComboBox), new PropertyMetadata(string.Empty, new PropertyChangedCallback(OnSelectedValuePathPropertyChanged)));
            SeparatorCharProperty = DependencyProperty.Register("SeparatorChar", typeof(string), typeof(CheckedComboBox), new PropertyMetadata(",", new PropertyChangedCallback(OnSeparatorCharPropertyChanged)));
            SelectionModeProperty = DependencyProperty.Register("SelectionMode", typeof(SelectionMode), typeof(CheckedComboBox), new PropertyMetadata(SelectionMode.Multiple, new PropertyChangedCallback(OnSelectionModePropertyChanged)));
        }
        public CheckedComboBox()
            : base()
        {
            this.DefaultStyleKey = typeof(CheckedComboBox);
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            this.IsDropDownOpen = false;
            this.ElementDropDownToggle = base.GetTemplateChild(ElementDropDownToggleName) as ToggleButton;
            this.ElementPopup = base.GetTemplateChild(ElementPopupName) as Popup;
            this.ElementContentPresenterBorder = base.GetTemplateChild(ElementContentPresenterBorderName) as FrameworkElement;
            this.ElementContentPresenter = base.GetTemplateChild(ElementContentPresenterName) as ContentPresenter;
            this.ElementItemsPresenter = base.GetTemplateChild(ElementItemsPresenterName) as ListBox;

            if (this.ElementItemsPresenter != null)
            {
                this.ElementItemsPresenter.SelectionChanged += new SelectionChangedEventHandler(ElementItemsPresenter_SelectionChanged);
                OnSelectedValueChanged(this.SelectedValue);
            }
            if (this.ElementDropDownToggle != null)
            {
                this.ElementDropDownToggle.IsTabStop = false;
                this.ElementDropDownToggle.Click += new RoutedEventHandler(this.ElementDropDownToggle_Click);
            }
            if (this.ElementPopup != null)
            {
                this.ElementPopupChild = this.ElementPopup.Child as FrameworkElement;
                this.ElementOutsidePopup = new Canvas();
            }
            else
            {
                this.ElementPopupChild = null;
                this.ElementOutsidePopup = null;
            }
            if (this.ElementOutsidePopup != null)
            {
                this.ElementOutsidePopup.Background = new SolidColorBrush(Colors.Transparent);
                this.ElementOutsidePopup.MouseLeftButtonDown += new MouseButtonEventHandler(this.ElementOutsidePopup_MouseLeftButtonDown);
            }
            KeyEventHandler handler = delegate(object sender, KeyEventArgs e)
            {
                this.OnKeyDown(e);
            };
            base.KeyDown += handler;
            base.SizeChanged += new SizeChangedEventHandler(this.ElementPopupChild_SizeChanged);
            if (this.ElementPopupChild != null)
            {
                this.ElementPopupChild.KeyDown += handler;
                this.ElementPopupChild.MouseEnter += new MouseEventHandler(this.ElementPopupChild_MouseEnter);
                this.ElementPopupChild.MouseLeave += new MouseEventHandler(this.ElementPopupChild_MouseLeave);
                this.ElementPopupChild.SizeChanged += new SizeChangedEventHandler(this.ElementPopupChild_SizeChanged);
                this.ElementPopupChildCanvas = new Canvas();
            }
            else
            {
                this.ElementPopupChildCanvas = null;
            }
            if ((this.ElementPopupChildCanvas != null) && (this.ElementOutsidePopup != null))
            {
                this.ElementPopup.Child = this.ElementPopupChildCanvas;
                this.ElementPopupChildCanvas.Children.Add(this.ElementOutsidePopup);
                this.ElementPopupChildCanvas.Children.Add(this.ElementPopupChild);
            }
            this.ChangeVisualState(false);
        }
        private void OnSelectedValueChanged(object selectedValue)
        {
            //未实现
            return;
            if (this.ElementItemsPresenter != null && !string.IsNullOrEmpty(this.SeparatorChar))
            {
                string valuePath = this.SelectedValuePath;
                if (!string.IsNullOrEmpty(valuePath))
                {
                    string[] array = selectedValue.ToString().Split(new string[] { this.SeparatorChar }, StringSplitOptions.None);
                    foreach (var item in this.ElementItemsPresenter.Items)
                    {
                        ListBoxItem lbi = this.ElementItemsPresenter.ItemContainerGenerator.ContainerFromItem(item) as ListBoxItem;

                        if (lbi != null)
                        {
                            Binding binding = new Binding(valuePath) { Source = item };
                            ContentControl temp = new ContentControl();
                            temp.SetBinding(ContentControl.ContentProperty, binding);

                            if (temp.Content != null)
                            {
                                foreach (var s in array)
                                {
                                    if (s.Equals(temp.Content.ToString()))
                                    {
                                        lbi.IsSelected = true; continue;
                                    }
                                }
                            }
                            temp.ClearValue(ContentControl.ContentProperty);
                        }
                    }
                }
            }
        }
        private void OnMaxDropDownHeightChanged(double newValue)
        {
            this.ArrangePopup();
            this.ChangeVisualState();
        }
        private void ArrangePopup()
        {
            if (((this.ElementPopup != null) && (this.ElementPopupChild != null)) && ((this.ElementContentPresenterBorder != null) && (this.ElementOutsidePopup != null)))
            {
                Content content = Application.Current.Host.Content;
                double actualWidth = content.ActualWidth;
                double actualHeight = content.ActualHeight;
                double num3 = this.ElementPopupChild.ActualWidth;
                double num4 = this.ElementPopupChild.ActualHeight;
                if ((actualHeight != 0.0) && (actualWidth != 0.0))
                {
                    GeneralTransform transform = null;
                    try
                    {
                        transform = this.ElementContentPresenterBorder.TransformToVisual(null);
                    }
                    catch
                    {
                        this.IsDropDownOpen = false;
                    }
                    if (transform != null)
                    {
                        Point point = new Point(0.0, 0.0);
                        Point point2 = new Point(1.0, 0.0);
                        Point point3 = new Point(0.0, 1.0);
                        Point point4 = transform.Transform(point);
                        Point point5 = transform.Transform(point2);
                        Point point6 = transform.Transform(point3);
                        double x = point4.X;
                        double y = point4.Y;
                        double num7 = Math.Abs((double)(point5.X - point4.X));
                        double num8 = Math.Abs((double)(point6.Y - point4.Y));
                        double num9 = base.ActualHeight * num8;
                        double num10 = base.ActualWidth * num7;
                        if ((num9 != 0.0) && (num10 != 0.0))
                        {
                            num3 *= num7;
                            num4 *= num8;
                            double maxDropDownHeight = this.MaxDropDownHeight;
                            if (double.IsInfinity(maxDropDownHeight) || double.IsNaN(maxDropDownHeight))
                            {
                                maxDropDownHeight = ((actualHeight - num9) * 3.0) / 5.0;
                            }
                            num3 = Math.Min(num3, actualWidth);
                            num4 = Math.Min(num4, maxDropDownHeight);
                            num3 = Math.Max(num10, num3);
                            double num12 = 0.0;
                            if (base.FlowDirection == FlowDirection.LeftToRight)
                            {
                                if (actualWidth < (x + num3))
                                {
                                    num12 = actualWidth - (num3 + x);
                                }
                            }
                            else if (0.0 > (x - num3))
                            {
                                num12 = x - num3;
                            }
                            bool flag = true;
                            double num13 = y + num9;
                            if (actualHeight < (num13 + num4))
                            {
                                flag = false;
                                num13 = y - num4;
                                if (num13 < 0.0)
                                {
                                    if (y < ((actualHeight - num9) / 2.0))
                                    {
                                        flag = true;
                                        num13 = y + num9;
                                    }
                                    else
                                    {
                                        flag = false;
                                        num13 = y - num4;
                                    }
                                }
                            }
                            if (num4 != 0.0)
                            {
                                if (flag)
                                {
                                    maxDropDownHeight = Math.Min(actualHeight - num13, maxDropDownHeight);
                                }
                                else
                                {
                                    maxDropDownHeight = Math.Min(y, maxDropDownHeight);
                                }
                            }
                            this.ElementPopup.HorizontalOffset = 0.0;
                            this.ElementPopup.VerticalOffset = 0.0;
                            this.ElementOutsidePopup.Width = actualWidth / num7;
                            this.ElementOutsidePopup.Height = actualHeight / num8;
                            Matrix identity = Matrix.Identity;
                            identity.OffsetX -= point4.X / num7;
                            identity.OffsetY -= point4.Y / num8;
                            MatrixTransform transform2 = new MatrixTransform
                            {
                                Matrix = identity
                            };
                            this.ElementOutsidePopup.RenderTransform = transform2;
                            double num14 = num10 / num7;
                            this.ElementPopupChild.MinWidth = num14;
                            this.ElementPopupChild.MaxWidth = Math.Max(num14, actualWidth / num7);
                            this.ElementPopupChild.MinHeight = num9 / num8;
                            this.ElementPopupChild.MaxHeight = Math.Max((double)0.0, (double)(maxDropDownHeight / num8));
                            this.ElementPopupChild.HorizontalAlignment = HorizontalAlignment.Left;
                            this.ElementPopupChild.VerticalAlignment = VerticalAlignment.Top;
                            Canvas.SetLeft(this.ElementPopupChild, num12 / num7);
                            Canvas.SetTop(this.ElementPopupChild, (num13 - y) / num8);
                        }
                    }
                }
            }
        }
        private void OnIsDropDownOpenChanged(bool isDropDownOpen)
        {
            //base.ItemContainerGenerator.StopAnimations();
            if (isDropDownOpen)
            {
                if (this.ElementPopup != null)
                {
                    this.ElementPopup.IsOpen = true;
                }
                if (this.ElementDropDownToggle != null)
                {
                    this.ElementDropDownToggle.IsChecked = true;
                }
                this.OnDropDownOpened(EventArgs.Empty);
            }
            else
            {
                if (this.ElementDropDownToggle != null)
                {
                    this.ElementDropDownToggle.IsChecked = false;
                }
                if (this.ElementPopup != null)
                {
                    this.ElementPopup.IsOpen = false;
                }
                this.OnDropDownClosed(EventArgs.Empty);
            }

            this.ChangeVisualState();
        }
        protected virtual void OnDropDownOpened(EventArgs e)
        {
            if (this.DropDownOpened != null)
            {
                this.DropDownOpened(this, e);
            }
        }
        protected virtual void OnDropDownClosed(EventArgs e)
        {
            if (this.DropDownClosed != null)
            {
                this.DropDownClosed(this, e);
            }
        }
        private void SetContentPresenter()
        {
            if (this.ElementContentPresenter != null)
            {
                this.ElementContentPresenter.Content = null;
            }

            string valuePath = SelectedValuePath;
            string displayPath = DisplayMemberPath;
            string valueTemp = string.Empty;
            string displayTemp = string.Empty;

            foreach (var item in ElementItemsPresenter.SelectedItems)
            {
                if (!string.IsNullOrEmpty(valuePath))
                {
                    Binding binding = new Binding(valuePath) { Source = item };
                    ContentControl temp = new ContentControl();
                    temp.SetBinding(ContentControl.ContentProperty, binding);
                    valueTemp = string.Format("{0}{1}{2}", valueTemp, SeparatorChar, temp.Content);

                    temp.ClearValue(ContentControl.ContentProperty);
                }
                else
                {
                    valueTemp = string.Format("{0}{1}{2}", valueTemp, SeparatorChar, item);
                }
                if (!string.IsNullOrEmpty(displayPath))
                {
                    Binding binding = new Binding(displayPath) { Source = item };
                    ContentControl temp = new ContentControl();
                    temp.SetBinding(ContentControl.ContentProperty, binding);
                    displayTemp = string.Format("{0}{1}{2}", displayTemp, SeparatorChar, temp.Content);
                    temp.ClearValue(ContentControl.ContentProperty);
                }
                else
                {
                    displayTemp = string.Format("{0}{1}{2}", displayTemp, SeparatorChar, item);
                }
            }
            SelectedValue = valueTemp.Length > 0 ? valueTemp.Remove(0, 1) : valueTemp;
            this.ElementContentPresenter.Content = displayTemp.Length > 0 ? displayTemp.Remove(0, 1) : displayTemp;
        }
        private void ElementItemsPresenter_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (e.AddedItems.Count > 0 || e.RemovedItems.Count > 0)
                SetContentPresenter();
            if (SelectionChanged != null)
            {
                SelectionChanged(this, e);
            }
        }
        private void ElementDropDownToggle_Click(object sender, RoutedEventArgs e)
        {
            if (base.IsEnabled)
            {
                base.Focus();
                bool? isChecked = this.ElementDropDownToggle.IsChecked;
                this.IsDropDownOpen = isChecked.HasValue ? isChecked.GetValueOrDefault() : false;
            }
        }
        private void ElementOutsidePopup_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            this.IsDropDownOpen = false;
        }
        private void ElementPopupChild_MouseEnter(object sender, MouseEventArgs e)
        {
            this._isMouseOverPopup = true;
            this.ChangeVisualState();
        }
        private void ElementPopupChild_MouseLeave(object sender, MouseEventArgs e)
        {
            this._isMouseOverPopup = false;
            this.ChangeVisualState();
        }
        private void ElementPopupChild_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            this.ArrangePopup();
        }

        #region override
        protected override void OnMouseEnter(MouseEventArgs e)
        {
            base.OnMouseEnter(e);
            this._isMouseOverMain = true;
            this.ChangeVisualState();
        }
        protected override void OnMouseLeave(MouseEventArgs e)
        {
            base.OnMouseLeave(e);
            this._isMouseOverMain = false;
            this.ChangeVisualState();
        }
        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            base.OnMouseLeftButtonDown(e);
            if (!e.Handled)
            {
                e.Handled = true;
                base.Focus();
                this.IsDropDownOpen = true;
            }
        }
        protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            base.OnItemsChanged(e);
            OnSelectedValueChanged(this.SelectedValue);
        }
        #endregion

        internal void ChangeVisualState()
        {
            this.ChangeVisualState(true);
        }
        private void ChangeVisualState(bool useTransitions)
        {
            if (!base.IsEnabled)
            {
    

相关文章

精彩推荐