Winform-绑定自定义类型对象下拉列表到DataGridViewComboBoxColumn


微软文档里自带的绑定对象到DataGridView示例,仅仅示例了枚举类型填充下拉列表。
关键代码:

DataGridViewComboBoxColumn CreateComboBoxWithEnums()
{
    DataGridViewComboBoxColumn combo = new DataGridViewComboBoxColumn();
    combo.DataSource = Enum.GetValues(typeof(Title));
    combo.DataPropertyName = "Title";
    combo.Name = "Title";
    return combo;
}

关键就是设置列对象的DataSource和DataPropertyName属性。
但是对于自定义类型,没有设置ToString()重载方法,因此必须通过设置DisplayMember属性来指定列的显示属性。
例如存在一个Title类

class Title
{
    public string Name{get;set;}
}

有一个类使用了Title类作为它的一个属性:

private class Knight
{
    private string hisName;
    private bool good;
    private Title hisTitle;

    public Knight(Title title, string name, bool good)
    {
        hisTitle = title;
        hisName = name;
        this.good = good;
    }

    public Knight()
    {
        hisTitle = Title.Sir;
        hisName = "";
        good = true;
    }

    public string Name
    {
        get
        {
            return hisName;
        }

        set
        {
            hisName = value;
        }
    }

    public bool GoodGuy
    {
        get
        {
            return good;
        }
        set
        {
            good = value;
        }
    }

    public Title Title
    {
        get
        {
            return hisTitle;
        }
        set
        {
            hisTitle = value;
        }
    }
}

当我们需要自定义一个Title列表作为可选的下拉列表时,对于此Knight.Title的属性对应的编辑列,按照如下的方式设置会提示Cell类型不正确。

private List titles = new List<Title>(){new Title(){Name = "Sir"},new Title(){Name = "King"}};
DataGridViewComboBoxColumn CreateComboBoxWithEnums()
{
    DataGridViewComboBoxColumn combo = new DataGridViewComboBoxColumn();
    combo.DataSource = this.titles;
    combo.DisplayMember = "Name";
    combo.DataPropertyName = "Title";
    combo.Name = "Title";
    return combo;
}
private void EnumsAndComboBox_Load(object sender, System.EventArgs e)
{
    // Populate the data source.
    bindingSource1.Add(new Knight(new Title(){Name = "King"}, "Uther", true));
    bindingSource1.Add(new Knight(new Title(){Name = "King"}, "Arthur", true));
    bindingSource1.Add(new Knight(new Title(){Name = "Sir"}, "Mordred", false));
    bindingSource1.Add(new Knight(new Title(){Name = "Sir"}, "Gawain", true));
    bindingSource1.Add(new Knight(new Title(){Name = "Sir"}, "Galahad", true));

    // Initialize the DataGridView.
    dataGridView1.AutoGenerateColumns = false;
    dataGridView1.AutoSize = true;
    dataGridView1.DataSource = bindingSource1;

    dataGridView1.Columns.Add(CreateComboBoxWithEnums());

    // Initialize and add a text box column.
    DataGridViewColumn column = new DataGridViewTextBoxColumn();
    column.DataPropertyName = "Name";
    column.Name = "Knight";
    dataGridView1.Columns.Add(column);

    // Initialize and add a check box column.
    column = new DataGridViewCheckBoxColumn();
    column.DataPropertyName = "GoodGuy";
    column.Name = "Good";
    dataGridView1.Columns.Add(column);

    // Initialize the form.
    this.Controls.Add(dataGridView1);
    this.AutoSize = true;
    this.Text = "DataGridView object binding demo";
}
</code></pre>
<p>因为设置了DisplayMember,必须设置ValueMember来指定下拉选择后设置此单元格对应的值属性。如果遇到需要将下拉列表选择的自定义类型对象(Title)设置为列表绑定对象(Knight)的属性值,无论ValueMember设置为null还是"",都无法返回自定义类型对象自身。<br>
解决办法搜索了很多,比较简单的办法是通过在Title中添加一个指向自身的属性,例如:</p>
<pre><code class="language-C#">public Title Self{get=>this;}
</code></pre>
<p>然后设置combo.ValueMember="Self"获取Title对象本身,缺点要修改Title的类结构。<br>
进阶方法是构建一个匿名类,一个属性保存显示属性,一个属性保存Title对象:</p>
<pre><code class="language-C#">combo.DataSource = this.titles.Select(t=>new(){Name = t.Name,Self=t}).ToList();
combo.DisplayMember = "Name";
combo.ValueMember = "Self";
</code></pre>
<p>缺点是匿名方法比较高版本的C#才有,取代方式是使用Tuple<string, Title>()元祖类</p>
<pre><code class="language-C#">combo.DataSource = this.titles.Select(t=>new Tuple<string, Title>(t.Name,t)).ToList();
combo.DisplayMember = "Item1";
combo.ValueMember = "Item2";
</code></pre>
						  
					  </div>
						<!--conend-->
							<div class="p-2"></div>

						<div class="arcinfo my-3 fs-7 text-center">
							
							
			<a href='/t/etagid1628-0.html' class='tagbtn' target='_blank'>Winform</a>							
						



						</div>
						
						<div class="p-2"></div>

						

						
					</div>
					<div class="p-2"></div>
					<!--xg-->
					<div class="lbox p-4 shadow-sm rounded-3">
						<div class="boxtitle"><h2 class="fs-4">相关</h2></div>
						
<hr>				
						
			<div class="row g-0 py-2 border-bottom align-items-center">
																
								<div class="col-7 col-lg-11 border-lg-end">
										<h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-561330.html">C# Winform表格DataGridView自定义列(文本列、ComboBox列)</a></h3>
									
									<div class="ltag fs-8 d-none d-lg-block">
								 

        </div>
								</div>
							
							</div><div class="row g-0 py-2 border-bottom align-items-center">
																
								<div class="col-7 col-lg-11 border-lg-end">
										<h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-560270.html">在winform的窗体上画图如何保证画的图像在切换界面或者最小化等操作时不会消失</a></h3>
									
									<div class="ltag fs-8 d-none d-lg-block">
								 

        </div>
								</div>
							
							</div><div class="row g-0 py-2 border-bottom align-items-center">
																
								<div class="col-7 col-lg-11 border-lg-end">
										<h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-559320.html">(八十)c#Winform自定义控件-分割线标签-HZHControls</a></h3>
									
									<div class="ltag fs-8 d-none d-lg-block">
								 

        </div>
								</div>
							
							</div><div class="row g-0 py-2 border-bottom align-items-center">
																
								<div class="col-7 col-lg-11 border-lg-end">
										<h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-559505.html">c#Winform自定义控件-目录-HZHControls</a></h3>
									
									<div class="ltag fs-8 d-none d-lg-block">
								 

        </div>
								</div>
							
							</div><div class="row g-0 py-2 border-bottom align-items-center">
																
								<div class="col-7 col-lg-11 border-lg-end">
										<h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-559174.html">(七十七)c#Winform自定义控件-采样控件-HZHControls</a></h3>
									
									<div class="ltag fs-8 d-none d-lg-block">
								 

        </div>
								</div>
							
							</div><div class="row g-0 py-2 border-bottom align-items-center">
																
								<div class="col-7 col-lg-11 border-lg-end">
										<h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-556721.html">MONO 如何打包 .NET程序独立运行(winform篇)</a></h3>
									
									<div class="ltag fs-8 d-none d-lg-block">
								 

        </div>
								</div>
							
							</div><div class="row g-0 py-2 border-bottom align-items-center">
																
								<div class="col-7 col-lg-11 border-lg-end">
										<h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-552511.html">(十四)c#Winform自定义控件-键盘(一)-HZHControls</a></h3>
									
									<div class="ltag fs-8 d-none d-lg-block">
								 

        </div>
								</div>
							
							</div><div class="row g-0 py-2 border-bottom align-items-center">
																
								<div class="col-7 col-lg-11 border-lg-end">
										<h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-552239.html">(二十一)c#Winform自定义控件-气泡提示-HZHControls</a></h3>
									
									<div class="ltag fs-8 d-none d-lg-block">
								 

        </div>
								</div>
							
							</div><div class="row g-0 py-2 border-bottom align-items-center">
																
								<div class="col-7 col-lg-11 border-lg-end">
										<h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-548379.html">GDI绘制Winform工作流组件、具有独立图层的增删处理、防PPT效果</a></h3>
									
									<div class="ltag fs-8 d-none d-lg-block">
								 

        </div>
								</div>
							
							</div><div class="row g-0 py-2 border-bottom align-items-center">
																
								<div class="col-7 col-lg-11 border-lg-end">
										<h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-532006.html">[转]c#中winform窗口的隐藏与显示</a></h3>
									
									<div class="ltag fs-8 d-none d-lg-block">
								 

        </div>
								</div>
							
							</div><div class="row g-0 py-2 border-bottom align-items-center">
																
								<div class="col-7 col-lg-11 border-lg-end">
										<h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-532025.html">问题:winform窗体与设计时不一致</a></h3>
									
									<div class="ltag fs-8 d-none d-lg-block">
								 

        </div>
								</div>
							
							</div><div class="row g-0 py-2 border-bottom align-items-center">
																
								<div class="col-7 col-lg-11 border-lg-end">
										<h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-522109.html">.Net6  winform 程序使用依赖注入</a></h3>
									
									<div class="ltag fs-8 d-none d-lg-block">
								 

        </div>
								</div>
							
							</div>            
            
            <!---->
                                    
           <!---->
  			
						

					</div>
					<!--xgend-->
				</div>

				<div class="col-lg-3 col-12 p-0 ps-lg-2">
					<!--box-->									
					<!--boxend-->
					<!--<div class="p-2"></div>-->

					<!--box-->
									<div class="lbox p-4 shadow-sm rounded-3">
					
									   <div class="boxtitle pb-2"><h2 class="fs-4"><a href="#">标签</a></h2></div>
										<div class="clearfix"></div>
										<ul class="m-0 p-0 fs-7 r-tag">
										</ul>
									

										
										<div class="clearfix"></div>
									</div>
					<!--box end-->

					
				</div>

			</div>
		
		
		
		</div>	

</main>
						<div class="p-2"></div>
<footer>
<div class="container-fluid p-0 bg-black">
	<div class="container p-0  fs-8">
	<p class="text-center m-0 py-2 text-white-50">一品网 <a class="text-white-50" href="https://beian.miit.gov.cn/" target="_blank">冀ICP备14022925号-6</a></p>
	</div>	
</div>
<script>
var _hmt = _hmt || [];
(function() {
  var hm = document.createElement("script");
  hm.src = "https://hm.baidu.com/hm.js?6e3dd49b5f14d985cc4c6bdb9248f52b";
  var s = document.getElementsByTagName("script")[0]; 
  s.parentNode.insertBefore(hm, s);
})();
</script>
</footer>
		
<script src="/skin/bootstrap.bundle.js"></script>

</body>
</html>