[英]Using ComboBox to show second-level properties in DataGridView
As I understand it, ComboBox columns are more dynamic for binding in DataGridView than standard columns, and this flexibility can be used to use DisplayMembers from second-order properties.据我了解,ComboBox 列在 DataGridView 中的绑定比标准列更具动态性,并且这种灵活性可用于使用二阶属性中的 DisplayMembers。 This approach is the first mentioned here by Mr. Aghaei .
这种方法是Aghaei先生在这里首次提到的。
However, I'm not getting it right.但是,我没有做对。 My application still throws the exception that "Name" doesn't exist.
我的应用程序仍然抛出“名称”不存在的异常。
public void CreateEmployeeTable()
{
DataGridViewComboBoxColumn jobTitleColumn = new DataGridViewComboBoxColumn();
jobTitleColumn.HeaderText = "Job Title";
jobTitleColumn.DataPropertyName = "JobTitle";
jobTitleColumn.DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing;
jobTitleColumn.DataPropertyName = "ID";
jobTitleColumn.DataSource = globalEmployeeList;
jobTitleColumn.ValueMember = "ID";
jobTitleColumn.DisplayMember = "Name";
jobTitleColumn.ReadOnly = true;
employeeGridView.AutoGenerateColumns = false;
employeeGridView.ColumnCount = 2;
employeeGridView.Columns[0].HeaderText = "Employee ID";
employeeGridView.Columns[0].DisplayIndex = 0;
employeeGridView.Columns[0].DataPropertyName = "ID";
employeeGridView.Columns[1].HeaderText = "Name";
employeeGridView.Columns[1].DataPropertyName = "ListView";
employeeGridView.Columns[1].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
employeeGridView.Columns.Add(jobTitleColumn);
employeeGridView.DataSource = globalEmployeeList;
}
Here is the class definition:这是 class 定义:
public class EmployeeModel
{
public int ID { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public string Nickname { get; set; }
public DepartmentModel Department { get; set; }
public TitleModel JobTitle { get; set; }
public DateTime HireDate { get; set; }
public List<EmailModel> EmailList { get; set; } = new List<EmailModel>();
public List<PhoneModel> PhoneList { get; set; } = new List<PhoneModel>();
public List<RestrictionModel> RestrictionsList { get; set; } = new List<RestrictionModel>();
public List<CitationModel> CitationsList { get; set; } = new List<CitationModel>();
public List<CertificationModel> CertificationList { get; set; } = new List<CertificationModel>();
public string ListView
{
get
{
return $"{LastName}, {FirstName}";
}
}
public string ToEmailString()
{
IEnumerable<string> employeeEmailStrings = EmailList.Select(emmod => emmod.ToString());
string employeeEmailString = string.Join($"{Environment.NewLine}", employeeEmailStrings);
IEnumerable<string> certificationStrings = CertificationList.Select(clistmod => clistmod.ToString());
string certificationString = string.Join($"{Environment.NewLine}", certificationStrings);
IEnumerable<string> phoneStrings = PhoneList.Select(plistmod => plistmod.ToString());
string phoneString = string.Join($"{Environment.NewLine}", phoneStrings);
return $"{FirstName}, {LastName}: {Environment.NewLine} -{JobTitle.Name}- {Environment.NewLine} {employeeEmailString} {Environment.NewLine} {certificationString} {Environment.NewLine} {phoneString}";
}
public class EmailModel
{
public int ID { get; set; }
public string Address { get; set; }
public string Type { get; set; }
public override string ToString()
{
return $"{Address} ({Type})";
}
}
public class PhoneModel
{
public int ID { get; set; }
public string Number { get; set; }
public string Type { get; set; }
public override string ToString()
{
return $"{Number} ({Type})";
}
}
}
And the definition for TitleModel: TitleModel 的定义:
public class TitleModel
{
public string Name { get; set; }
public int ID { get; set; }
}
}
To support the post Show Properties of a Navigation Property in DataGridView (Second Level Properties) I've already shared a few example in the same post or this one which allows showing second level properties and allow editing them.为了支持在 DataGridView 中显示导航属性的属性(二级属性) ,我已经在同一篇文章或这个允许显示二级属性并允许编辑它们的示例中共享了一些示例。
Here I will share a few more examples, each example has been written as a minimal complete verifiable example, you can just copy and paste in an empty form and they will work.在这里我将分享更多示例,每个示例都被编写为一个最小的完整可验证示例,您只需复制并粘贴到一个空表单中,它们就可以工作。
These are the examples:这些是示例:
When: You don't want to change JobTitle
of Employee何时:您不想更改 Employee 的
JobTitle
How: By overriding ToString
method of JobTitle
如何:通过覆盖
JobTitle
的ToString
方法
class JobTitle
{
public int Id { get; set; }
public string Name { get; set; }
public override string ToString()
{
return Name;
}
}
class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public JobTitle JobTitle { get; set; }
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
var jobTitles = new List<JobTitle>() {
new JobTitle {Id= 1, Name="Manager" },
new JobTitle {Id= 2, Name="Employee" },
};
var employees = new List<Employee>() {
new Employee{ Id = 1, Name ="John", JobTitle = jobTitles[0] },
new Employee{ Id = 2, Name ="Jane", JobTitle = jobTitles[1] },
new Employee{ Id = 3, Name ="Jack", JobTitle = jobTitles[1] },
};
var dg = new DataGridView();
dg.Dock = DockStyle.Fill;
dg.DataSource = employees;
this.Controls.Add(dg);
}
When: You don't want to change JobTitle
of Employee何时:您不想更改 Employee 的
JobTitle
How: By handling CellFormatting
event of DataGridView
and setting Value
of the event args to a string representation of JobTitle
如何:通过处理
DataGridView
的CellFormatting
事件并将事件 args 的Value
设置为JobTitle
的字符串表示形式
class JobTitle
{
public int Id { get; set; }
public string Name { get; set; }
}
class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public JobTitle JobTitle { get; set; }
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
var jobTitles = new List<JobTitle>() {
new JobTitle {Id= 1, Name="Manager" },
new JobTitle {Id= 2, Name="Employee" },
};
var employees = new List<Employee>() {
new Employee{ Id = 1, Name ="John", JobTitle = jobTitles[0] },
new Employee{ Id = 2, Name ="Jane", JobTitle = jobTitles[1] },
new Employee{ Id = 3, Name ="Jack", JobTitle = jobTitles[1] },
};
var dg = new DataGridView();
dg.Dock = DockStyle.Fill;
dg.DataSource = employees;
dg.CellFormatting += (obj, args) =>
{
if (args.RowIndex >= 0 &&
dg.Columns[args.ColumnIndex].DataPropertyName == "JobTitle")
args.Value = ((Employee)dg.Rows[args.RowIndex].DataBoundItem).JobTitle.Name;
};
this.Controls.Add(dg);
}
When: You want to be able to change the JobTitle
of Employee
and you have the foreign key column in your model.何时:您希望能够更改
Employee
的JobTitle
并且您的 model 中有外键列。
How: Using a DataGridViewComboBoxColumn
for that property, having a data source containing all job titles, and setting DisplayMember
and ValueMember
to proper properties.方法:对该属性使用
DataGridViewComboBoxColumn
,拥有一个包含所有职位的数据源,并将DisplayMember
和ValueMember
设置为适当的属性。
class JobTitle
{
public int Id { get; set; }
public string Name { get; set; }
}
class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public int JobTitleId { get; set; }
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
var jobTitles = new List<JobTitle>() {
new JobTitle {Id= 1, Name="Manager" },
new JobTitle {Id= 2, Name="Employee" },
};
var employees = new List<Employee>() {
new Employee{ Id = 1, Name ="John", JobTitleId = 1 },
new Employee{ Id = 2, Name ="Jane", JobTitleId = 2 },
new Employee{ Id = 2, Name ="Jack", JobTitleId = 2 },
};
var dg = new DataGridView();
dg.Dock = DockStyle.Fill;
dg.DataSource = employees;
dg.Columns.Add(new DataGridViewTextBoxColumn()
{
DataPropertyName = "Id", HeaderText = "Id"
});
dg.Columns.Add(new DataGridViewTextBoxColumn()
{
DataPropertyName = "Name", HeaderText = "Name"
});
dg.Columns.Add(new DataGridViewComboBoxColumn()
{
DataPropertyName = "JobTitleId",
HeaderText = "JobTitleId",
DataSource = jobTitles,
ValueMember = "Id",
DisplayMember = "Name",
});
this.Controls.Add(dg);
}
When: You want to be able to change the JobTitle
of Employee
and you don't have the foreign key column in your model, instead you want to use the navigation object in your model.何时:您希望能够更改
Employee
的JobTitle
并且您的 model 中没有外键列,而是希望在 Z20F35E630DAF44DBFA4C3F68F5399D8C8 中使用导航 object。
How: Using a DataGridViewComboBoxColumn
for that property, having a data source containing all job titles, without setting DisplayMember
and ValueMember
to proper properties.方法:对该属性使用
DataGridViewComboBoxColumn
,具有包含所有职位的数据源,无需将DisplayMember
和ValueMember
设置为适当的属性。 Then handling CellFormatting
to set the display value of the cell and handling CellParsing
to get value from ComboBox
and put into the cell.然后处理
CellFormatting
设置单元格的显示值,处理CellParsing
从ComboBox
获取值并放入单元格。
class JobTitle
{
public int Id { get; set; }
public string Name { get; set; }
public override string ToString()
{
return Name;
}
}
class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public JobTitle JobTitle { get; set; }
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
var jobTitles = new List<JobTitle>() {
new JobTitle {Id= 1, Name="Manager" },
new JobTitle {Id= 1, Name="Employee" },
};
var employees = new List<Employee>() {
new Employee{ Id = 1, Name ="John", JobTitle = jobTitles[0] },
new Employee{ Id = 2, Name ="Jane", JobTitle = jobTitles[1] },
new Employee{ Id = 2, Name ="Jack", JobTitle = jobTitles[1] },
};
var dg = new DataGridView();
dg.Dock = DockStyle.Fill;
dg.DataSource = employees;
dg.Columns.Add(new DataGridViewTextBoxColumn()
{
DataPropertyName = "Id", HeaderText = "Id"
});
dg.Columns.Add(new DataGridViewTextBoxColumn()
{
DataPropertyName = "Name", HeaderText = "Name"
});
dg.Columns.Add(new DataGridViewComboBoxColumn()
{
DataPropertyName = "JobTitle",
HeaderText = "JobTitle",
DataSource = jobTitles,
});
dg.CellFormatting += (obj, args) =>
{
if (args.RowIndex >= 0 &&
dg.Columns[args.ColumnIndex].DataPropertyName == "JobTitle")
{
args.Value =
((Employee)dg.Rows[args.RowIndex].DataBoundItem).JobTitle.ToString();
}
};
dg.CellParsing += (obj, args) =>
{
if (args.RowIndex >= 0 &&
dg.Columns[args.ColumnIndex].DataPropertyName == "JobTitle")
{
args.Value = ((ComboBox)dg.EditingControl).SelectedItem;
args.ParsingApplied = true;
}
};
this.Controls.Add(dg);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.