第一种格式:使用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;
}
}
#endregionstatic 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);
}
#endregioninternal void ChangeVisualState()
{
this.ChangeVisualState(true);
}
private void ChangeVisualState(bool useTransitions)
{
if (!base.IsEnabled)
{