一、前言

先看看 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. jQuery学习之路(2)-DOM操作

    ▓▓▓▓▓▓ 大致介绍 jQuery作为JavaScript库,继承并发扬了JavaScript对DOM对象操作的特性,使开发人员能方便的操作DOM对象. ▓▓▓▓▓▓ jQuery中的DOM操作 看 ...

  2. LeetCode[5] 最长的回文子串

    题目描述 Given a string S, find the longest palindromic substring in S. You may assume that the maximum ...

  3. 创建APPID&&部署服务端教程

    创建APPID&&部署服务端 一.创建APPID 1.打开https://console.developers.google.com ,左击顶部Project,然后左击创建项目 2.输 ...

  4. C# 用SoapUI调试WCF服务接口(WCF中包含用户名密码的验证)

    问题描述: 一般调试wcf程序可以直接建一个单元测试,直接调接口. 但是,这次,我还要测试在接口内的代码中看接收到的用户名密码是否正确,所以,单一的直接调用接口方法行不通, 然后就想办法通过soapU ...

  5. PAT甲级 1001. A+B Format (20)

    题目原文: Calculate a + b and output the sum in standard format -- that is, the digits must be separated ...

  6. 【Linux大系】Linux的概念与体系

    感谢原作者:Vamei 出处:http://www.cnblogs.com/vamei 我在这一系列文章中阐述Linux的基 本概念.Linux操作系统继承自UNIX.一个操作系统是一套控制和使用计算 ...

  7. Lind.DDD.LindAspects方法拦截的介绍

    回到目录 什么是LindAspects 之前写了关于Aspects的文章<Lind.DDD.Aspects通过Plugins实现方法的动态拦截~Lind里的AOP>,今天主要在设计思想上进 ...

  8. 【SAP业务模式】之ICS(六):发票输出类型

    这篇开始主要讲述发票输出类型: 首先我们新建一个发票类型,用于公司间的发票MIV,而标准的发票类型还是F2保持不变: 一.新建发票类型: 目录:SPRO-销售与分销-出具发票-开票凭证-定义出具发票类 ...

  9. iOS从零开始学习直播之3.美颜

      任何一款直播软件都必须进行美颜,不然哪来的那么多美女,所以技术改变世界,不只是说说而已.美颜在采集的时候就得就行,让主播实时看到直播的效果. 1.美颜原理   其实美颜的本质就是美白和磨皮,分别通 ...

  10. javaMail

    JavaMail概述:        JavaMail是由Sun定义的一套收发电子邮件的API,不同的厂商可以提供自己的实现类.但它并没有包含在JDK中,而是作为JavaEE的一部分. javaMai ...