[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代码 解决:在视图消失 ...
随机推荐
- Unity3D框架插件uFrame实践记录(二)
5.创建属性和命令 本小节主要内容包括: 在Element节点上创建属性数据 在Element节点上创建命令数据 5.1.在Element节点上创建属性数据 在这里,我们首先为Login节点中的属性( ...
- Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
学习架构探险,从零开始写Java Web框架时,在学习到springAOP时遇到一个异常: "C:\Program Files\Java\jdk1.7.0_40\bin\java" ...
- 嵌入式&iOS:回调函数(C)与block(OC)回调对比
学了OC的block,再写C的回调函数有点别扭,对比下区别,回忆记录下. C的回调函数: callBack.h 1).定义一个回调函数的参数数量.类型. typedef void (*CallBack ...
- NDK开发_笔记0
自谷歌搜索退出中国以来,谷歌对全球第二大市场中国的态度一直保持冷淡.可是北京时间12月8日,谷歌2016开发者大会在北京召开,同时专门针对中国的谷歌开发者网站已经上线:https://develope ...
- Linux:将rhel yum 切换到centos yum
Red Hat Enterprise Linux Server(RHEL) yum安装软件时This system is not registered with RHN. RHN support wi ...
- JavaScript中的this
本文尽量避免概念性的讲解,那样太抽象 所以下面以一些简单的例子,从易到难对this的用法总结 1.方法中的this会指向当前执行该方法的对象 如: var name = "window&qu ...
- SpringMVC初步
SpringMVC框架介绍 1) Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面. Spring 框架提供了构建 Web 应用程序的全功 ...
- smartcrop.js智能图片裁剪库
今天将为大家介绍一款近期github上很不错的开源库 – smartcrop.js.它是一款图片处理的智能裁剪库.在很多项目开发中,经常会遇见上传图片的场景,它可能是用户照片信息,也可能是商品图片等. ...
- 布里斯班Twilight Bay Run半程马拉松
自从8月3日跑了半马以后,又一鼓作气报了11月份的西昌马拉松.与第一次马拉松的只求完赛目标不同,第二次当然想取得一个更好的成绩.所以8月份练的比较猛,基本上是练2.3天休息一天,周么还要拉个长于21公 ...
- 【Java并发编程实战】-----“J.U.C”:Exchanger
前面介绍了三个同步辅助类:CyclicBarrier.Barrier.Phaser,这篇博客介绍最后一个:Exchanger.JDK API是这样介绍的:可以在对中对元素进行配对和交换的线程的同步点. ...