您的位置:首页 > 运维架构

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

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

问题描述

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



选择左边任意一个列表项后,再选择一个PBS模板

切换左边列表项后,发现右边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 == null) return;
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."

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

回顾

对于未知问题,可以通过现象猜测可能出现的点

如果项目本身复杂不易调试,可以针对问题点做一个简答Demo来验证问题点的猜测是否正确

通过.Net框架源码逐步调试可以看到内部代码执行流,比使用Reflector查看静态代码方便好用

更多内容:

[b] 开源信息系统开发平台之OpenExpressApp框架.pdf[/b][/i]

欢迎转载,转载请注明:转载自周金根 [ http://zhoujg.cnblogs.com/ ]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息