[C1] C1ComboBox 的非编辑状态优化
一、前言
先看看 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 的非编辑状态优化的更多相关文章
- odoo14 编辑状态和非编辑状态下隐藏
1 <div class="oe_edit_only"> 2 <a name="remove_group_id" type="obj ...
- cxgrid 非编辑状态下复制当前列的值 真折腾人
1.自带的CTRL +C 只能复制整行,不知是不是版本问题. 2.有分组这个代码就不行了 s:= G1DBView.DataController.Values[G1DBView.Controller. ...
- iOS开发UI篇-tableView在编辑状态下的批量操作(多选)
先看下效果图 直接上代码 #import "MyController.h" @interface MyController () { UIButton *button; } @pr ...
- EasyUI的datagrid获取所有正在编辑状态的行的行编号
今天项目需要用了下EasyUI的datagrid的行编辑功能,跟着API来,只要是将各种状态时的处理逻辑弄好,还是蛮不错的. 开发过程中,遇到了个问题,在编辑完成后我需要获取datagrid所有处于编 ...
- Easyui 设置datagrid 进入编辑状态,保存结束编辑
在datagrid中如何实现让一行进入编辑状态,修改数据后,保存信息呢? //点击列表变成文本框,进入可编辑状态 $(function () { var doc = $(document), tabl ...
- WPF 编辑状态切换
有时候DataGrid编辑的时候一个属性需要根据别的属性呈现不同的编辑状态.这就需要一个做一个状态切换.比如地址是1的时候,读写类型是读写.只读.只写.地址是2的时候,就只读.状态栏切换为TextBo ...
- MVC编辑状态两个DropDownList联动
前几天使用jQuery在MVC应用程序中,实现了<jQuery实现两个DropDownList联动(MVC)>http://www.cnblogs.com/insus/p/3414480. ...
- datagrid combobox事件更新编辑状态下的datagrid行
请问如何从上图状态 点击下拉的combobox中值然后在不取消datagrid编辑状态下更新这一行另一列的数据,达到下图这样的效果: 非常感谢! 给你的combobox 绑定一个onSelect 事 ...
- iOS7 iOS8 UITableviewCell处于编辑状态,dismiss或者back崩溃
今天在项目中遇到一个坑爹的 Crash , 在 iOS7 iOS8 UITableviewCell处于编辑状态,dismiss或者back崩溃 iOS9不会 原因:苹果的BUG代码 解决:在视图消失 ...
随机推荐
- 引人瞩目的 CSS 变量(CSS Variable)
这是一个令人激动的革新. CSS 变量,顾名思义,也就是由网页的作者或用户定义的实体,用来指定文档中的特定变量. 更准确的说法,应该称之为 CSS 自定义属性 ,不过下文为了好理解都称之为 CSS 变 ...
- 通过VMware的PowerCLI配置集群内指定主机的vMotion功能
PowerCLI是VMware开发的基于微软(MSFT)的PowerShell的命令行管理vSphere的实现,因此在批量化操作方面CLI会减轻很多GUI环境下的繁琐重复劳作. 现有场景中有大量的物理 ...
- the Zen of Python---转载版
摘自译文学习区 http://article.yeeyan.org/view/legendsland/154430 The Zen of Python Python 之禅 Beautiful is b ...
- iOS开发 判断当前APP版本和升级
从iOS8系统开始,用户可以在设置里面设置在WiFi环境下,自动更新安装的App.此功能大大方便了用户,但是一些用户没有开启此项功能,因此还是需要在程序里面提示用户的 方法一:在服务器接口约定对应的数 ...
- Java 教程整理:基础、项目全都有
Java 在编程语言排行榜中一直位列前排,可知 Java 语言的受欢迎程度了. 网上有很多 Java 教程,无论是基础入门还是开发小项目的教程都比比皆是,可是系统的很少,对于Java 学习者来说找到系 ...
- linux下配置matlab运行环境(MCR)
在安装好的matlab下有MCR(MatlabCompilerRuntime)在matlab2011/toolbox/compiler/deploy/glnxa64下找到MCRInstaller.zi ...
- DDD设计中的Unitwork与DomainEvent如何相容?
最近在开发过程中,遇到了一个场景,甚是棘手,在这里分享一下.希望大家脑洞大开一起来想一下解决思路.鄙人也想了一个方案拿出来和大家一起探讨一下是否合理. 一.简单介绍一下涉及的对象概念 工作单元:维护变 ...
- 运用Mono.Cecil 反射读取.NET程序集元数据
CLR自带的反射机智和API可以很轻松的读取.NET程序集信息,但是不能对程序集进行修改.CLR提供的是只读的API,但是开源项目Mono.Cecil不仅仅可以读取.NET程序集的元数据,还可以进行修 ...
- Linux下部署ASP.NET服务连接oracle遇到的问题记录
一.如何卸载MONO Q:mono是linux系统上跨平台软件,卸载它有两种方式: 1.知道mono安装路径,安装原来的路径直接覆盖安装(最为简单): 2.不知道mono安装路径,首先通过sudo f ...
- 关于asp.net利用mono部署到Linux上的一些说明
linuxdot.net社区群:102732979(如果你认为你已经在.NET跨平台方面有足够的经验,请参加这个群:103810355). 其中有各种大神,嘿嘿,如果你有问题可以来咨询,完全无偿的免费 ...