ComboBox DisplayMember无法赋值的问题

来源:互联网 发布:深圳十六号公寓知乎 编辑:程序博客网 时间:2024/06/05 16:41

我的遇到的例子是两个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就会变成""空字符串。由于发生的情况太多了,所以大家根据自己的情况进行判断吧。


0 0
原创粉丝点击