一、前言

先看看 WPF 自带的 ComboBox 在非编辑状态,自定义 ItemTemplate 的情况下,效果如下图所示:

[C1] C1ComboBox 的非编辑状态优化

其当前选中的项(红框内)与自定义的 ItemTemplate 一样;

但是 C1ComboBox 的非编辑状态(IsEditable="False"):

[C1] C1ComboBox 的非编辑状态优化

总感觉它的非编辑状态并没有完成,虽然数字和英文无法输入,但在红框内依旧可以输入中文文本(QQ拼音输入法的中文输入状态)[C1] C1ComboBox 的非编辑状态优化;并且在非编辑状态下并非像 Combobox 的非编辑状态可以显示自定义的 ItemTemplate 效果;这篇文章就介绍如何使用 C1ComboBox 模仿 ComboBox 的非编辑状态效果。

二、解决方案

先分析 C1ComboBox 的控件结构:

[C1] C1ComboBox 的非编辑状态优化

其中 ComboHeader 部分是由两个控件来回切换显示的,

internal C1TextBoxBase _elementEditControl;
internal ContentPresenter _elementContentControl;

_elementEditControl 则是编辑状态下显示的控件,_elementContentControl 则是非编辑状态下显示的控件(可显示自定义的 ItemTemplate);

而这两个控件转换显示的方法如下(C1TextEditableContentControl):

  1 protected internal void UpdateVisualState()
  2 {
  3     if (this.EditControl == null || this.ContentControl == null)
  4     {
  5         return;
  6     }
  7     if (this.IsInEditMode || this.IsDropDownOpen)
  8     {
  9         this.EditControl.Opacity = 1.0;
 10         this.EditControl.IsTabStop = true;
 11         this.EditControl.IsHitTestVisible = true;
 12         this.ContentControl.Visibility = Visibility.Collapsed;
 13         this.ContentControl.Content = null;
 14     }
 15     else
 16     {
 17         this.EditControl.Opacity = 1.4012984643248171E-45;
 18         this.EditControl.IsTabStop = false;
 19         this.EditControl.IsHitTestVisible = false;
 20         this.ContentControl.Visibility = Visibility.Visible;
 21         this.ContentControl.Content = this.ActualContent;
 22     }
 23     base.Cursor = (this.IsEditable ? Cursors.IBeam : Cursors.Arrow);
 24 }
 25 // 注:EditControl对应_elementEditControl,ContentControl对应_elementContentControl;

即,当 this.IsInEditMode || this.IsDropDownOpen 为 false 时,方可显示自定义的 Itemplate ;

所以,当 ScrollViewer 收缩时(IsDropDownOpen 为 false),设置 ComboHeader 的 IsInEditMode 为 false, 即可保证下拉选择项后,在 ComboHeader 显示自定义的 ItemTemplate;

Loaded += (sender, e) =>
{
    C1TextEditableContentControl editBox = GetChildObjects<C1TextEditableContentControl>(cmb, typeof(C1TextEditableContentControl))[0];
    cmb.IsDropDownOpenChanged += (sender2, e2) =>
    {
        editBox.IsInEditMode = false;
    };
};
  1 public List<T> GetChildObjects<T>(DependencyObject obj, Type typename) where T : FrameworkElement
  2 {
  3     DependencyObject child = null;
  4     List<T> childList = new List<T>();
  5 
  6     for (int i = 0; i <= VisualTreeHelper.GetChildrenCount(obj) - 1; i++)
  7     {
  8         child = VisualTreeHelper.GetChild(obj, i);
  9 
 10         if (child is T && (((T)child).GetType() == typename))
 11         {
 12             childList.Add((T)child);
 13         }
 14         childList.AddRange(GetChildObjects<T>(child, typename));
 15     }
 16     return childList;
 17 }
GetChildObjects方法

相关文章: