ComboBox DisplayMember无法赋值的问题

博客讨论了在C#中ComboBox DisplayMember无法赋值的问题,特别是在设置DataSource后。作者通过Resharper查看源码,发现DisplayMember不能直接赋值,而ValueMember可以。文章提到了一个可能的解决方案,并在后续更新中引用了MSDN文档,详细解释了DataSource和DisplayMember的关系以及触发的事件。最后,作者揭示了问题的根源在于特定条件下的DataSource变更会导致DisplayMember变为空字符串。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值