我的遇到的例子是两个combobox的联动,类似地址的选择,在选择了国家之后就出现省份一样。这个可以参考(遇到的问题的描述,和最后一个回帖是一样的)
我是用resharp(一个非常好用的vs插件)查看了代码之后,得出的结论:
一开始我的代码是这个顺序的:
<pre name="code" class="csharp">cb_goodsType.DisplayMember = "Value";
cb_goodsType.ValueMember = "Key";
cb_goodsType.DataSource = goodsTypeList;
修改后的顺序是这样的
cb_goodsType.DataSource = goodsTypeList;
cb_goodsType.DisplayMember = "Value";
cb_goodsType.ValueMember = "Key";
就是datasource的顺序掉到了最前面。想快速解决问题的可以这样试试,想知道原因的继续向下看(源代码也是一知半解):
DisplayMember不可以赋值,但ValueMember是可以赋值的,那么自然想到displayMember的设置肯定有问题,去看看源码:、
public string DisplayMember
{
get
{
return this.displayMember.BindingMember;
}
set
{
BindingMemberInfo bindingMemberInfo = this.displayMember;
try
{
this.SetDataConnection(this.dataSource, new BindingMemberInfo(value), false);
}
catch
{
this.displayMember = bindingMemberInfo;
}
}
}
在这里可以看到里面有一个try,catch在里面有一个setDataConnection,里面肯定有问题,应该是throw了什么异常,再进入去看:
private void SetDataConnection(object newDataSource, BindingMemberInfo newDisplayMember, bool force)
{
bool flag1 = this.dataSource != newDataSource;
bool flag2 = !this.displayMember.Equals((object) newDisplayMember);
if (this.inSetDataConnection)
return;
try
{
if (force || flag1 || flag2)
{
this.inSetDataConnection = true;
IList list = this.DataManager != null ? this.DataManager.List : (IList) null;
bool flag3 = this.DataManager == null;
this.UnwireDataSource();
this.dataSource = newDataSource;
this.displayMember = newDisplayMember;
this.WireDataSource();
if (this.isDataSourceInitialized)
{
CurrencyManager currencyManager = (CurrencyManager) null;
if (newDataSource != null && this.BindingContext != null && newDataSource != Convert.DBNull)
currencyManager = (CurrencyManager) this.BindingContext[newDataSource, newDisplayMember.BindingPath];
if (this.dataManager != currencyManager)
{
if (this.dataManager != null)
{
this.dataManager.ItemChanged -= new ItemChangedEventHandler(this.DataManager_ItemChanged);
this.dataManager.PositionChanged -= new EventHandler(this.DataManager_PositionChanged);
}
this.dataManager = currencyManager;
if (this.dataManager != null)
{
this.dataManager.ItemChanged += new ItemChangedEventHandler(this.DataManager_ItemChanged);
this.dataManager.PositionChanged += new EventHandler(this.DataManager_PositionChanged);
}
}
if (this.dataManager != null && (flag2 || flag1) && (this.displayMember.BindingMember != null && this.displayMember.BindingMember.Length != 0 && !this.BindingMemberInfoInDataManager(this.displayMember)))
throw new ArgumentException(SR.GetString("ListControlWrongDisplayMember"), "newDisplayMember");
if (this.dataManager != null && (flag1 || flag2 || force) && (flag2 || force && (list != this.dataManager.List || flag3)))
this.DataManager_ItemChanged((object) this.dataManager, new ItemChangedEventArgs(-1));
}
this.displayMemberConverter = (TypeConverter) null;
}
if (flag1)
this.OnDataSourceChanged(EventArgs.Empty);
if (!flag2)
return;
this.OnDisplayMemberChanged(EventArgs.Empty);
}
finally
{
this.inSetDataConnection = false;
}
}
看完这个代码之后灵光一现想出来的方法,但时间过太久了,忘记了怎么想出来的,有知道的人希望在评论处回复一下,让我补充
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2015年5月13日
一条华丽的分割线之后,今天又遇到了displaymember和datasource设置的问题,上面扯了这么多还没有官方的文档来得清楚和干净利落:
这是msdn上的截图,这里清楚的解析的datasource和displayMember的关系和会触发的事件。附上链接
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
经过今天对源码的再次查看,终于发现了,问题的根源,上面贴的第一段代码出现了致命的问题(贴错了)。下面再重新贴过:
public new object DataSource
{
get
{
return base.DataSource;
}
set
{
base.DataSource = value;
}
}
在comboBox中的Datasource是这样写的,但在源码中并没有看到调用datasourcechanged的函数的调用,那么再看看,这些datasource的来源都是父类,再进入父类再看看,父类是一个ListControl
public object DataSource
{
get
{
return this.dataSource;
}
set
{
if (value != null && !(value is IList) && !(value is IListSource))
throw new ArgumentException(SR.GetString("BadDataSourceForComplexBinding"));
if (this.dataSource == value)
return;
try
{
this.SetDataConnection(value, this.displayMember, false);
}
catch
{
this.DisplayMember = "";
}
if (value != null)
return;
this.DisplayMember = "";
}
}
看到这里就清晰了,其实上面的代码应该是贴这段的,不然怎么会说看throw就好了,但displaymember和datasource都调用了this.SetDataConnection这个函数,导致了贴错代码。再向下看:
private void SetDataConnection(object newDataSource, BindingMemberInfo newDisplayMember, bool force)
{
bool flag1 = this.dataSource != newDataSource;
bool flag2 = !this.displayMember.Equals((object) newDisplayMember);
if (this.inSetDataConnection)
return;
try
{
if (force || flag1 || flag2)
{
this.inSetDataConnection = true;
IList list = this.DataManager != null ? this.DataManager.List : (IList) null;
bool flag3 = this.DataManager == null;
this.UnwireDataSource();
this.dataSource = newDataSource;
this.displayMember = newDisplayMember;
this.WireDataSource();
if (this.isDataSourceInitialized)
{
CurrencyManager currencyManager = (CurrencyManager) null;
if (newDataSource != null && this.BindingContext != null && newDataSource != Convert.DBNull)
currencyManager = (CurrencyManager) this.BindingContext[newDataSource, newDisplayMember.BindingPath];
if (this.dataManager != currencyManager)
{
if (this.dataManager != null)
{
this.dataManager.ItemChanged -= new ItemChangedEventHandler(this.DataManager_ItemChanged);
this.dataManager.PositionChanged -= new EventHandler(this.DataManager_PositionChanged);
}
this.dataManager = currencyManager;
if (this.dataManager != null)
{
this.dataManager.ItemChanged += new ItemChangedEventHandler(this.DataManager_ItemChanged);
this.dataManager.PositionChanged += new EventHandler(this.DataManager_PositionChanged);
}
}
if (this.dataManager != null && (flag2 || flag1) && (this.displayMember.BindingMember != null && this.displayMember.BindingMember.Length != 0 && !this.BindingMemberInfoInDataManager(this.displayMember)))
throw new ArgumentException(SR.GetString("ListControlWrongDisplayMember"), "newDisplayMember");
if (this.dataManager != null && (flag1 || flag2 || force) && (flag2 || force && (list != this.dataManager.List || flag3)))
this.DataManager_ItemChanged((object) this.dataManager, new ItemChangedEventArgs(-1));
}
this.displayMemberConverter = (TypeConverter) null;
}
if (flag1)
this.OnDataSourceChanged(EventArgs.Empty);
if (!flag2)
return;
this.OnDisplayMemberChanged(EventArgs.Empty);
}
finally
{
this.inSetDataConnection = false;
}
}
再看回这段代码,这次真的就看throw就好了,所有赋值不成功的都是这里出了问题。
1、dataManager是有新有旧的,但这个也没有问题,重点是只要你设置了正确的datasource,这个datamanager就应该不为null的
2、flag1 这个就是新的datasource和旧的datasource的对比
3、两个displaymember的对比
4、后面的参数基本上都是true的
只要判断flag1和flag2其中一个是true,那么就会导致exception的发生,这样displaymember就会变成""空字符串。由于发生的情况太多了,所以大家根据自己的情况进行判断吧。