[WPF] 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):

  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方法

但是,当 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;

  1 private void UpdateSwappedOut()
  2 {
  3     if (this._elementComboHeader == null)
  4     {
  5         return;
  6     }
  7     this._elementComboHeader.IsDropDownOpen = this.IsDropDownOpen;
  8     C1ComboBoxItem c1ComboBoxItem = null;
  9     this._isHeaderUpdate = true;
 10     this._elementComboHeader.ActualContent = null;
 11     this._isHeaderUpdate = false;
 12     this._elementComboHeader.UpdateIsWatermarked();
 13     this._elementComboHeader.UpdateVisualState();
 14     if (this.SwappedOutItem != null)
 15     {
 16         this.SwappedOutItem.SwappedOut = false;
 17         this.SwappedOutItem = null;
 18     }
 19     if (this.SelectedItem == null)
 20     {
 21         return;
 22     }
 23     if (this.SelectedIndex != -1)
 24     {
 25         c1ComboBoxItem = (C1ComboBoxItem)base.ItemContainerGenerator.ContainerFromIndex(this.SelectedIndex);
 26         if (c1ComboBoxItem != null && !this.IsDropDownOpen)
 27         {
 28             this.SwappedOutItem = c1ComboBoxItem;
 29             c1ComboBoxItem.SwappedOut = true;
 30         }
 31     }
 32     if (c1ComboBoxItem == null)
 33     {
 34         c1ComboBoxItem = (this.SelectedItem as C1ComboBoxItem);
 35     }
 36     this._isHeaderUpdate = true;
 37     if (c1ComboBoxItem == null)
 38     {
 39         if (base.ItemStringFormat != null && !this.IsEditable && base.ItemTemplate == null)
 40         {
 41             this._elementComboHeader.ActualContent = this.FormattedString(base.ItemStringFormat, this.SelectedItem);
 42         }
 43         else
 44         {
 45             this._elementComboHeader.ActualContent = this.SelectedItem;
 46         }
 47     }
 48     else if (base.ItemStringFormat != null && !this.IsEditable && base.ItemTemplate == null)
 49     {
 50         this._elementComboHeader.ActualContent = this.FormattedString(base.ItemStringFormat, c1ComboBoxItem.Content);
 51     }
 52     else
 53     {
 54         this._elementComboHeader.ActualContent = c1ComboBoxItem.Content;
 55     }
 56     this._isHeaderUpdate = false;
 57     this._elementComboHeader.IsDirty = false;
 58 }

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

  1 private void UpdateVisualState()
  2 {
  3     if (this.EditControl == null || this.ContentControl == null)
  4     {
  5         return;
  6     }
  7     this.EditControl.Opacity = 1.4012984643248171E-45;
  8     this.EditControl.IsTabStop = false;
  9     this.EditControl.IsHitTestVisible = false;
 10     this.ContentControl.Visibility = Visibility.Visible;
 11     C1ComboBoxItem cmbi = ((C1ComboBoxItem)cmb.ItemContainerGenerator.ContainerFromIndex(cmb.SelectedIndex));
 12     this.ContentControl.Content = cmbi.Content;
 13     base.Cursor = (EditBox.IsEditable ? Cursors.IBeam : Cursors.Arrow);
 14 }
  1 EditControl = GetChildObjects<Control>(cmb, "EditControl")[0];
  2 ContentControl = GetChildObjects<ContentPresenter>(cmb, "ContentControl")[0];
  3 cmb.IsDropDownOpenChanged += (sender2, e2) =>
  4 {
  5     // EditBox.IsInEditMode = false;
  6     UpdateVisualState();
  7 };
  1 public List<T> GetChildObjects<T>(DependencyObject obj, string name) 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).Name == name | string.IsNullOrEmpty(name)))
 11         {
 12             childList.Add((T)child);
 13         }
 14         childList.AddRange(GetChildObjects<T>(child, name));
 15     }
 16     return childList;
 17 }

一切Over,效果如下:

初始状态:

展开状态:

选择项改变后状态:

三、资源下载

1、Demo工程下载:http://files.cnblogs.com/files/memento/C1ComboBoxSample.7z

时间: 2024-08-09 18:37:20

[WPF] C1ComboBox的非编辑状态的相关文章

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

1.自带的CTRL +C 只能复制整行,不知是不是版本问题. 2.有分组这个代码就不行了 s:= G1DBView.DataController.Values[G1DBView.Controller.FocusedRowIndex ,G1DBView.Controller.FocusedColumnIndex]; 3.折腾后的方案: uses Clipbrd; procedure TForm28.Button1Click(Sender: TObject); var s:string; //.Fo

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

先看下效果图 直接上代码 #import "MyController.h" @interface MyController () { UIButton *button; } @property(nonatomic,strong)NSMutableArray *array;//数据源 @property (nonatomic,strong)NSMutableArray *selectorPatnArray;//存放选中数据 @end @implementation MyControlle

JTable只要一双击就进入编辑状态,禁止的方法实现

我用JTable做了一个表格,表格内容只供查看和选择,可每次只要一双击,就进入编辑状态,可是现在我不需要当双击的时候修改表格的内容.这时候需要重载isCellEditable方法. 下面是我的实现的代码: DefaultTableModel model = new DefaultTableModel(date, columnNames) { public boolean isCellEditable(int row, int column) { return false; } }; 这样设置的话

winform如何实现一个窗体显示后,他的窗体处于不可编辑状态

1)可以使用this.Enabled = false;是窗体处于不可编辑状态. 2)使用showDialog(),showDialog()是一个对话框窗口界面```执行结果以新窗口界面出现```不允许进行后台运行```就是你想编辑什么的时候```非得先关闭showDialog()窗口界面才可以进行其他操作

玩转web之JQuery(二)---改变表单和input的可编辑状态(封装的js)

var FormDeal = { /** * 功能 :将表单的所有input都设为可编辑的 *@param 要操作表单的id */ formWritable: function (formId) { $("#"+formId+" input,textarea").removeAttr("readonly"); $("#"+formId+" input,textarea").css('backgroundCo

easyui 在编辑状态下,动态修改其他列值。

1 首先是自定义了一个方法uodateColumn更新列值 2 3 /** 4 *自定义的修改列值方法 5 */ 6 $.extend($.fn.datagrid.methods, { 7 updateColumn: function(datagrid,data) { 8 datagrid.each(function(){ 9 //获取缓存中的配置数据 10 var gridObj=$.data(this,"datagrid"); 11 var opts=gridObj.options

DevExpress XtraGrid网格控件示例三:获取当前处于编辑状态的值

使用下面的示例代码,以获得当前编辑的值. C# 1 string editingValue; 2 if(gridControl1.KeyboardFocusView.IsEditing) 3 editingValue = gridControl1.KeyboardFocusView.EditingValue.ToString(); DevExpress XtraGrid网格控件示例三:获取当前处于编辑状态的值,布布扣,bubuko.com

编辑crontab -e无法退出编辑状态

在进入crontab -e进入编辑状态时,会提示使用哪一种编辑器. 如果选择使用/bin/nano,那么在编辑完后退出时,应按Ctrl+X,这时会提示是否保存,输入Y,就保存退出啦.

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

今天在项目中遇到一个坑爹的 Crash , 在 iOS7 iOS8 UITableviewCell处于编辑状态,dismiss或者back崩溃  iOS9不会 原因:苹果的BUG代码 解决:在视图消失之前把编辑状态设为NO -(void)viewDidDisappear:(BOOL)animated{    [superviewDidDisappear:animated];    self.shoppingBagTableView.editing = NO;  /** ios7 ios8 编辑状