前一阵子写了好几篇处理WPF内存泄漏和bug的blog,本篇继续,主要围绕一下ComboBox的绑定问题来讲,通过此bug的分析和解决过程,希望能给大家对处理bug带来一些思路。
在OpenExpressApp中一直没有注意,测试人员提交了一个bug,现象是这样的:
既然是下拉列表操作后出现问题,那么我就在下拉操作时设置了一个断点,我加了一条更新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."
但要注意:这仅是清除单向绑定
更多内容: 开源信息系统开发平台之OpenExpressApp框架.pdf
欢迎转载,转载请注明:转载自周金根 [ http://zhoujg.cnblogs.com/ ]