前一阵子写了好几篇处理WPF内存泄漏和bug的blog,本篇继续,主要围绕一下ComboBox的绑定问题来讲,通过此bug的分析和解决过程,希望能给大家对处理bug带来一些思路。

问题描述

  在OpenExpressApp中一直没有注意,测试人员提交了一个bug,现象是这样的:

信息系统开发平台OpenExpressApp - 如何解决ComboBox.TextProperty绑定带来问题的来龙去脉_第1张图片

  1. 选择左边任意一个列表项后,再选择一个PBS模板
  2. 切换左边列表项后,发现右边PBS模板显示为空白,没有内容

发现问题

  既然是下拉列表操作后出现问题,那么我就在下拉操作时设置了一个断点,我加了一条更新ComboBox文本框内容的代码,想看看是否有效果:

 

this._cmbGrid.GetBindingExpression(ComboBox.TextProperty).UpdateTarget()

  运行后竟然发现报空对象引用错误this._cmbGrid.GetBindingExpression(ComboBox.TextProperty)获取的是个空对象。如果熟悉OpenExpressApp的AutoUI设计的应该知道,在编辑器控件生成时会给生成控件进行Text绑定,按道理应该不会出现绑定不了的问题,既然出现了,那么就最可能是绑定出现了问题。

  那么问题处在哪呢?我突然想起,会不会是因为直接给ComboBox的Text属性赋值导致,由于直接赋值而清空绑定

简化问题

  上面只是一个猜测,可能是Text赋值后导致,于是做了一个简单的程序,只是一个combox控件和button控件,在button上写了以下代码:

 

            cb.SetBinding(ComboBox.TextProperty, b);
            cb.GetBindingExpression(ComboBox.TextProperty).UpdateTarget();
            cb.Text = "111";
            cb.GetBindingExpression(ComboBox.TextProperty).UpdateTarget();

  发现果然是在Text赋值后就会清空TextProperty的数据绑定。为了查看在哪里清除,我用了在下载.Net4 Framework源码,查找OpenExpressApp中DataGrid枚举值更新错误的原因中介绍的方法,逐步调试到DependencyObject单元,发现执行到一段代码,具体代码还没有太看明白,我估摸着是清空绑定,如果有谁清晰的话回复一下吧。

 

                // detach the old expression, if applicable 
                if (currentExpr != null)
                { 
                    // CALLBACK 
                    DependencySource[] currentSources = currentExpr.GetSources();
 
                    UpdateSourceDependentLists(this, dp, currentSources, currentExpr, false);  // Remove

                    // CALLBACK
                    currentExpr.OnDetach(this, dp); 
                    currentExpr.MarkDetached();

                    entryIndex = CheckEntryIndex(entryIndex, dp.GlobalIndex); 
                }

解决问题

  既然知道了原因是TextBinding被清空了,那么剩下的就是我们如何在框架中处理了,解决这个问题很简单,每个属性编辑器都有一个View对象,那么我们只要在每次切换列表时重新绑定一次就好了,修改代码如下:

        public LookupListPropertyEditor(BusinessObjectPropertyInfo propertyInfo, IObjectView view)
            : base(propertyInfo, view) 
        {
            this.View.CurrentObjectChanged += new EventHandler(View_CurrentObjectChanged);
        }


        void View_CurrentObjectChanged(object sender, EventArgs e)
        {
            CreateTextBinding();
        }

        //由于直接对ComboBox.Text直接赋值,导致TextBinding Detach,所以需要手动新增绑定
        private void CreateTextBinding()
        {
            if (_cmbGrid == nullreturn;
            var bindExpr = this._cmbGrid.GetBindingExpression(ComboBox.TextProperty);
            if (bindExpr == null)
            {
                Binding textBinding = new Binding();
                this.PrepareBinding(textBinding);
                PrepareBinding(textBinding);
                this._cmbGrid.SetBinding(ComboBox.TextProperty, textBinding);
            }
            else
                bindExpr.UpdateTarget();
  }

知识点

  解决问题后,在《WPF揭秘》一书196页中发现写到:

另一种清除绑定的方式是直接为目标属性设置一个新的值,例如: currentFolder.Text = "I am no longer receiving updates."

但要注意:这仅是清除单向绑定

回顾

  1. 对于未知问题,可以通过现象猜测可能出现的点
  2. 如果项目本身复杂不易调试,可以针对问题点做一个简答Demo来验证问题点的猜测是否正确
  3. 通过.Net框架源码逐步调试可以看到内部代码执行流,比使用Reflector查看静态代码方便好用

 

更多内容: 开源信息系统开发平台之OpenExpressApp框架.pdf

 

欢迎转载,转载请注明:转载自周金根 [ http://zhoujg.cnblogs.com/ ]