集合编辑器不响应 PropertyValueChanged 事件的处理方式

今天又接到个新需求,客户要求在propertygrid上做的设计改动在另外一个窗体能实时显示结果,一开始很简单,因为我知道这个控件PropertyValueChanged事件,我要做的无非就是实现这个事件而已,花了点时间实现后感觉一切都挺好,满足要求了,然而好死不死,测试的时候遇到对一个集合对象的编辑,妥妥的打脸啊,属性怎么改都不会触发PropertyValueChanged事件,网上查一下,发现集合是个引用类型,修改了集合的Item,其实并没有修改集合对象的引用地址,而Propertygrid里是通过!=来判断的,所以导致PropertyValueChanged不会触发,然后又翻了下CollectionEditor的源码,发现又是内部类,有事私有类,看样子也没办法重写了,但是客户的需求必须实现啊,谁给钱谁是老大啊,后来想到反正所有的变更都是在set属性后在发生的,我是不是可以在这个上面做文章.

 

想到就动手,一个个在set属性里写肯定是不行的,辣么多类,辣么多属性写死人,想了想决定使用代理来拦截set动作,并在拦截器里触发PropertyValueChanged,又花了点时间做完了,找了集合类做了下测试,发现效果不错,目的达到了,然后准备把所有涉及到集合的类都修改成这个样子,这时候问题来了,因为要实现AOP代理,需要让被代理的类继承ContextBoundObject并且加上AopAttribute特性,然而有些类本身就已经继承于一个封装类了,再让它继承ContextBoundObject在C#语法里妥妥的行不通滴,到此该方案直接夭折.(做之前不动脑,考虑太片面~浪费时间.)

 

在死掉大半脑细胞后,突然想起来上一篇文章CollectionEditor集合编辑器使用中讲到通过反射使属性描述区域显示出来,灵光一闪,妥了,主的propertygrid是因为编辑的是一个引用集合所以没办法触发PropertyValueChanged,但是CollectionEditor里编辑的可是集合里的项,肯定是可以触发CollectionEditor里的propertygrid对应的PropertyValueChanged事件的,写完代码,测试通过,下面贴上代码

  1 public class CollectionEditorExpansion : CollectionEditor
  2     {
  3         public delegate void ValueChangeHandler();
  4 
  5         public static event ValueChangeHandler OnValueChange;
  6 
  7         public CollectionEditorExpansion(Type type) : base(type)
  8         {
  9         }
 10         protected override CollectionForm CreateCollectionForm()
 11         {
 12             //获取form对象
 13             CollectionForm frm = base.CreateCollectionForm();
 14             //获取属性浏览器对象
 15             FieldInfo fileinfo = frm.GetType().GetField("propertyBrowser", BindingFlags.NonPublic | BindingFlags.Instance);
 16             if (fileinfo != null)
 17             {
 18                 PropertyGrid pgrid = (fileinfo.GetValue(frm) as PropertyGrid);
 19                 pgrid.HelpVisible = true;
 20                 pgrid.PropertyValueChanged += Pgrid_PropertyValueChanged;
 21                 pgrid.SelectedObjectsChanged += ExtendCollectionEditor_ValueChange;
 22             }
 23             frm.Width = 700;
 24             frm.Height = 600;
 25 
 26             #region 注册按钮事件
 27             FieldInfo removeButton = frm.GetType().GetField("removeButton", BindingFlags.NonPublic | BindingFlags.Instance);
 28             if (removeButton != null)
 29             {
 30                 (removeButton.GetValue(frm) as Button).Click += ExtendCollectionEditor_RemoveClick;
 31             }
 32 
 33             FieldInfo cancelButton = frm.GetType().GetField("cancelButton", BindingFlags.NonPublic | BindingFlags.Instance);
 34             if (cancelButton != null)
 35             {
 36                 (cancelButton.GetValue(frm) as Button).Click += ExtendCollectionEditor_ValueChange;
 37             }
 38 
 39             FieldInfo okButton = frm.GetType().GetField("okButton", BindingFlags.NonPublic | BindingFlags.Instance);
 40             if (okButton != null)
 41             {
 42                  
43
} 44 FieldInfo upButton = frm.GetType().GetField("upButton", BindingFlags.NonPublic | BindingFlags.Instance); 45 if (upButton != null) 46 { 47
48
} 49 FieldInfo downButton = frm.GetType().GetField("downButton", BindingFlags.NonPublic | BindingFlags.Instance); 50 if (downButton != null) 51 { 52
53
} 54 #endregion 55 return frm; 56 } 57 #region 反射事件 58 private void ExtendCollectionEditor_ValueChange(object sender, EventArgs e) 59 { 60 SubmitChange(); 61 } 62 63 protected void ExtendCollectionEditor_RemoveClick(object sender, EventArgs e) 64 { 65 CollectionForm frm = (sender as Button).Parent.Parent.Parent as CollectionForm; 66 FieldInfo listbox = frm.GetType().GetField("listbox", BindingFlags.NonPublic | BindingFlags.Instance); 67 ListBox listb = listbox.GetValue(frm) as ListBox; 68 69 PropertyInfo Items = frm.GetType().GetProperty("Items", BindingFlags.NonPublic | BindingFlags.Instance); 70 PropertyInfo ListItem =null; 71 72 object[] items = new object[listb.Items.Count]; 73 for (int i = 0; i < listb.Items.Count; i++) 74 { 75 if (ListItem == null) 76 { 77 ListItem= listb.Items[i].GetType().GetProperty("Value", BindingFlags.Public | BindingFlags.Instance); 78 } 79 items[i] = ListItem.GetValue(listb.Items[i]); 80 } 81 82 Items.SetValue(frm, items); 83 84 AfterRemove(); 85 } 86 87 private void Pgrid_PropertyValueChanged(object s, PropertyValueChangedEventArgs e) 88 { 89 SubmitChange(); 90 } 91 #endregion 92 93 #region 方法 94 /// <summary> 95 /// 移除对象后触发 96 /// </summary> 97 protected virtual void AfterRemove() 98 { 99 SubmitChange(); 100 } 101 102 private void SubmitChange() 103 { 104 OnValueChange?.Invoke(); 105 } 106 #endregion 107 }

代码里还有一个特殊的按钮removeButton,这个按钮在执行的时候是并没有直接操作集合对象,而且先把要移除的对象通过一个arraylist对象缓存起来,仅修改显示的listbox的集合界面,所以不管是主的propertygrid还是CollectionEditor中的propertygrid都无法响应对应操作,只要在点击onbutton或者cancelbutton的之后才会触发真正的修改,这也没办法满足客户的需求,因此,在removeClick的事件里针对这个按钮做了下特殊处理

posted @ 2017-02-22 10:10  fengylm  阅读(1740)  评论(2编辑  收藏  举报