一、前言

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

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

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

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

二、解决方案

先分析 C1ComboBox 的控件结构:

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

internal C1TextBoxBase _elementEditControl;
internal ContentPresenter _elementContentControl;

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

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

 protected internal void UpdateVisualState()
{
if (this.EditControl == null || this.ContentControl == null)
{
return;
}
if (this.IsInEditMode || this.IsDropDownOpen)
{
this.EditControl.Opacity = 1.0;
this.EditControl.IsTabStop = true;
this.EditControl.IsHitTestVisible = true;
this.ContentControl.Visibility = Visibility.Collapsed;
this.ContentControl.Content = null;
}
else
{
this.EditControl.Opacity = 1.4012984643248171E-45;
this.EditControl.IsTabStop = false;
this.EditControl.IsHitTestVisible = false;
this.ContentControl.Visibility = Visibility.Visible;
this.ContentControl.Content = this.ActualContent;
}
base.Cursor = (this.IsEditable ? Cursors.IBeam : Cursors.Arrow);
}
// 注: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;
};
};
 public List<T> GetChildObjects<T>(DependencyObject obj, Type typename) where T : FrameworkElement
{
DependencyObject child = null;
List<T> childList = new List<T>(); for (int i = 0; i <= VisualTreeHelper.GetChildrenCount(obj) - 1; i++)
{
child = VisualTreeHelper.GetChild(obj, i); if (child is T && (((T)child).GetType() == typename))
{
childList.Add((T)child);
}
childList.AddRange(GetChildObjects<T>(child, typename));
}
return childList;
}

GetChildObjects方法

但是,当 ComboHeader 获取焦点,仍然会显示 EditControl ,而不是 ContentControl,所以添加如下代码:

editBox.IsEditable = false;
editBox.GotFocus += (sender2, e2) =>
{
editBox.IsInEditMode = false;
};

需要注意的是,如果不设置 editBox.IsEditable = false; ,点击两次 ComboHeader 还是会进入编辑状态,显示 EditControl 的……

继续但是,当点击 ArrowToggle 按钮展开 ScrollViewer 时,仍旧会显示编辑状态,这个就麻烦了,查看源码可知,该操作时会触发 UpdateSwappedOut 方法以修改 _elementComboHeader 的 ActualContent ,进而触发上面的 UpdateVisualState 方法,而此时 ScrollViewer 的 IsDropDownOpen 属性为 true,导致显示编辑状态,而非自定义的 ItemTemplate;

 private void UpdateSwappedOut()
{
if (this._elementComboHeader == null)
{
return;
}
this._elementComboHeader.IsDropDownOpen = this.IsDropDownOpen;
C1ComboBoxItem c1ComboBoxItem = null;
this._isHeaderUpdate = true;
this._elementComboHeader.ActualContent = null;
this._isHeaderUpdate = false;
this._elementComboHeader.UpdateIsWatermarked();
this._elementComboHeader.UpdateVisualState();
if (this.SwappedOutItem != null)
{
this.SwappedOutItem.SwappedOut = false;
this.SwappedOutItem = null;
}
if (this.SelectedItem == null)
{
return;
}
if (this.SelectedIndex != -1)
{
c1ComboBoxItem = (C1ComboBoxItem)base.ItemContainerGenerator.ContainerFromIndex(this.SelectedIndex);
if (c1ComboBoxItem != null && !this.IsDropDownOpen)
{
this.SwappedOutItem = c1ComboBoxItem;
c1ComboBoxItem.SwappedOut = true;
}
}
if (c1ComboBoxItem == null)
{
c1ComboBoxItem = (this.SelectedItem as C1ComboBoxItem);
}
this._isHeaderUpdate = true;
if (c1ComboBoxItem == null)
{
if (base.ItemStringFormat != null && !this.IsEditable && base.ItemTemplate == null)
{
this._elementComboHeader.ActualContent = this.FormattedString(base.ItemStringFormat, this.SelectedItem);
}
else
{
this._elementComboHeader.ActualContent = this.SelectedItem;
}
}
else if (base.ItemStringFormat != null && !this.IsEditable && base.ItemTemplate == null)
{
this._elementComboHeader.ActualContent = this.FormattedString(base.ItemStringFormat, c1ComboBoxItem.Content);
}
else
{
this._elementComboHeader.ActualContent = c1ComboBoxItem.Content;
}
this._isHeaderUpdate = false;
this._elementComboHeader.IsDirty = false;
}

没辙,没找到如何禁止触发 UpdateSwappedOut 方法,或者触发后如何设置 IsDropDownOpen 为 false,所以就把 EditControl 和 ContentControl 两个控件拿出来,再自己写一个 UpdateVisualState 来更新两个状态的转换;

 private void UpdateVisualState()
{
if (this.EditControl == null || this.ContentControl == null)
{
return;
}
this.EditControl.Opacity = 1.4012984643248171E-45;
this.EditControl.IsTabStop = false;
this.EditControl.IsHitTestVisible = false;
this.ContentControl.Visibility = Visibility.Visible;
C1ComboBoxItem cmbi = ((C1ComboBoxItem)cmb.ItemContainerGenerator.ContainerFromIndex(cmb.SelectedIndex));
this.ContentControl.Content = cmbi.Content;
base.Cursor = (EditBox.IsEditable ? Cursors.IBeam : Cursors.Arrow);
}
 EditControl = GetChildObjects<Control>(cmb, "EditControl")[0];
ContentControl = GetChildObjects<ContentPresenter>(cmb, "ContentControl")[0];
cmb.IsDropDownOpenChanged += (sender2, e2) =>
{
// EditBox.IsInEditMode = false;
UpdateVisualState();
};
 public List<T> GetChildObjects<T>(DependencyObject obj, string name) where T : FrameworkElement
{
DependencyObject child = null;
List<T> childList = new List<T>(); for (int i = 0; i <= VisualTreeHelper.GetChildrenCount(obj) - 1; i++)
{
child = VisualTreeHelper.GetChild(obj, i); if (child is T && (((T)child).Name == name | string.IsNullOrEmpty(name)))
{
childList.Add((T)child);
}
childList.AddRange(GetChildObjects<T>(child, name));
}
return childList;
}

一切Over,效果如下:

初始状态:

展开状态:

选择项改变后状态:

[C1] C1ComboBox 的非编辑状态优化的更多相关文章

  1. odoo14 编辑状态和非编辑状态下隐藏

    1 <div class="oe_edit_only"> 2 <a name="remove_group_id" type="obj ...

  2. cxgrid 非编辑状态下复制当前列的值 真折腾人

    1.自带的CTRL +C 只能复制整行,不知是不是版本问题. 2.有分组这个代码就不行了 s:= G1DBView.DataController.Values[G1DBView.Controller. ...

  3. iOS开发UI篇-tableView在编辑状态下的批量操作(多选)

    先看下效果图 直接上代码 #import "MyController.h" @interface MyController () { UIButton *button; } @pr ...

  4. EasyUI的datagrid获取所有正在编辑状态的行的行编号

    今天项目需要用了下EasyUI的datagrid的行编辑功能,跟着API来,只要是将各种状态时的处理逻辑弄好,还是蛮不错的. 开发过程中,遇到了个问题,在编辑完成后我需要获取datagrid所有处于编 ...

  5. Easyui 设置datagrid 进入编辑状态,保存结束编辑

    在datagrid中如何实现让一行进入编辑状态,修改数据后,保存信息呢? //点击列表变成文本框,进入可编辑状态 $(function () { var doc = $(document), tabl ...

  6. WPF 编辑状态切换

    有时候DataGrid编辑的时候一个属性需要根据别的属性呈现不同的编辑状态.这就需要一个做一个状态切换.比如地址是1的时候,读写类型是读写.只读.只写.地址是2的时候,就只读.状态栏切换为TextBo ...

  7. MVC编辑状态两个DropDownList联动

    前几天使用jQuery在MVC应用程序中,实现了<jQuery实现两个DropDownList联动(MVC)>http://www.cnblogs.com/insus/p/3414480. ...

  8. datagrid combobox事件更新编辑状态下的datagrid行

    请问如何从上图状态 点击下拉的combobox中值然后在不取消datagrid编辑状态下更新这一行另一列的数据,达到下图这样的效果: 非常感谢! 给你的combobox  绑定一个onSelect 事 ...

  9. iOS7 iOS8 UITableviewCell处于编辑状态,dismiss或者back崩溃

    今天在项目中遇到一个坑爹的 Crash , 在 iOS7 iOS8 UITableviewCell处于编辑状态,dismiss或者back崩溃  iOS9不会 原因:苹果的BUG代码 解决:在视图消失 ...

随机推荐

  1. javascript:逆波兰式表示法计算表达式结果

    逆波兰式表示法,是由栈做基础的表达式,举个例子: 5 1 2 + 4 * + 3 -  等价于   5 + ((1 + 2) * 4) - 3 原理:依次将5 1 2 压入栈中, 这时遇到了运算符 + ...

  2. JS图片上传预览插件制作(兼容到IE6)

    其实,图片预览功能非常地常见.很意外,之前遇到上传图片的时候都不需要预览,也一直没有去实现过.现在手上的项目又需要有图片预览功能,所以就动手做了一个小插件.在此分享一下思路. 一.实现图片预览的一些方 ...

  3. 敏捷转型历程 - Sprint3 Grooming

    我: Tech Leader 团队:团队成员分布在两个城市,我所在的城市包括我有4个成员,另外一个城市包括SM有7个成员.另外由于我们的BA离职了,我暂代IT 的PO 职位.PM和我在一个城市,但他不 ...

  4. BZOJ 3083: 遥远的国度 [树链剖分 DFS序 LCA]

    3083: 遥远的国度 Time Limit: 10 Sec  Memory Limit: 1280 MBSubmit: 3127  Solved: 795[Submit][Status][Discu ...

  5. java根据html生成摘要

    转自:http://java.freesion.com/article/48772295755/ 开发一个系统,需要用到这个,根据html生成你指定多少位的摘要 package com.chendao ...

  6. 我的MYSQL学习心得(十七) 复制

    我的MYSQL学习心得(十七) 复制 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据 ...

  7. CYQ.Data V5 从入门到放弃ORM系列:教程 - MProc类使用

    MProc介绍 MProc:是一个用于执行SQL或存储过程的数据库操作类,它轻量高性能地类似于Dapper. MProc:它出现的场景很少,因为MAction自身就能处理掉90%-100%的数据操作( ...

  8. 【Knockout.js 学习体验之旅】(2)花式捆绑

    本文是[Knockout.js 学习体验之旅]系列文章的第2篇,所有demo均基于目前knockout.js的最新版本(3.4.0).小茄才识有限,文中若有不当之处,还望大家指出. 目录: [Knoc ...

  9. 如何设计一门语言(七)——闭包、lambda和interface

    人们都很喜欢讨论闭包这个概念.其实这个概念对于写代码来讲一点用都没有,写代码只需要掌握好lambda表达式和class+interface的语义就行了.基本上只有在写编译器和虚拟机的时候才需要管什么是 ...

  10. 2、利用蓝牙定位及姿态识别实现一个智能篮球场套件(二)——CC2540/CC2541基于广播的RSSI获得

    CC2541一拖多例程中RSSI获得是通过一个事件回调函数实现的,前提是需要连接上蓝牙设备. 这个对于多点定位来说是不可行的,由于主机搜索蓝牙设备过程中也能获得当前蓝牙设备的RSSI等信息,因此可基于 ...