C# DataGridView不显示包含列表的属性

C# DataGridView不显示包含列表的属性,c#,datagridview,C#,Datagridview,我有一个这样的目标 public class Person{ public int ID { get; set; } public string Name{ get; set; } public string Surname{ get; set; } public List<int> AltIDs { get; set; } public List<string&g

我有一个这样的目标

public class Person{
        public int ID { get; set; }                 
        public string Name{ get; set; }
        public string Surname{ get; set; }
        public List<int> AltIDs { get; set; }
        public List<string> AltNames{ get; set; }   
}
然而,我在DataGridView中只看到了3列,分别是ID、名称和姓氏,带有List和List的属性似乎被忽略了。
有没有办法让这些属性显示在DataGridView中?可能喜欢逗号分隔的值。

最有可能的人是空的 您只需像这样更改代码

第一个解决方案:

您的型号:

public class Person
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string Surname { get; set; }
    public List<int> AltIDs { get; set; }
    public List<string> AltNames { get; set; }
}
public class Person
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string Surname { get; set; }
    public List<int> AltIDs { get; set; }
    public List<string> AltNames { get; set; }
}
formLoad:

private void Form1_Load(object sender, EventArgs e)
    {
        List<Person> people = new List<Person>() 
        {new Person(){ ID=1,Name="a",Surname="a",AltIDs=new List<int>(){1,2,3,4 },AltNames=new List<string>(){"a","b","c" } },
        new Person(){ ID=2,Name="b",Surname="b",AltIDs=new List<int>(){10,20,30,40 },AltNames=new List<string>(){"a","b","c" }},
        new Person(){ ID=3,Name="c",Surname="c",AltIDs=new List<int>(){100,200,300,400 },AltNames=new List<string>(){"a","b","c" }},
        new Person(){ ID=4,Name="d",Surname="d",AltIDs=new List<int>(){1000,2000,3000,4000 },AltNames=new List<string>(){"a","b","c" }},
        new Person(){ ID=3,Name="e",Surname="e",AltIDs=new List<int>(){10000,20000,30000,40000 },AltNames=new List<string>(){"a","b","c" }}
        };
        List<PersonViewModel> pwm = new List<PersonViewModel>();
        foreach (var person in people)
        {
           foreach(var id in person.AltIDs)
            {
                foreach (var name in person.AltNames)
                    pwm.Add(new PersonViewModel() { ID = person.ID, Name = person.Name, Surname = person.Surname, AltID = id, AltName = name });
            }
        }
        dgv.DataSource = pwm;

    }
FormLoad:

 private void Form1_Load(object sender, EventArgs e)
    {
        List<Person> people = new List<Person>() 
        {new Person(){ ID=1,Name="a",Surname="a",AltIDs=new List<int>(){1,2,3,4 },AltNames=new List<string>(){"a","b","c" } },
        new Person(){ ID=2,Name="b",Surname="b",AltIDs=new List<int>(){10,20,30,40 },AltNames=new List<string>(){"a","b","c" }},
        new Person(){ ID=3,Name="c",Surname="c",AltIDs=new List<int>(){100,200,300,400 },AltNames=new List<string>(){"a","b","c" }},
        new Person(){ ID=4,Name="d",Surname="d",AltIDs=new List<int>(){1000,2000,3000,4000 },AltNames=new List<string>(){"a","b","c" }},
        new Person(){ ID=3,Name="e",Surname="e",AltIDs=new List<int>(){10000,20000,30000,40000 },AltNames=new List<string>(){"a","b","c" }}
        };
        List<PersonViewModel> pwm = new List<PersonViewModel>();
        StringBuilder sbIds;
        StringBuilder sbNames;
        foreach (var person in people)
        {
            sbIds = new StringBuilder();
            sbNames = new StringBuilder();
            person.AltIDs.ForEach(c=> sbIds.Append(c.ToString()).Append(","));
            person.AltNames.ForEach(c=> sbNames.Append(c).Append(","));
            pwm.Add(new PersonViewModel() { ID = person.ID, Name = person.Name, Surname = person.Surname, AltID = sbIds.ToString().TrimEnd(','), AltName = sbNames.ToString().TrimEnd(',') });                
        }
        dgv.DataSource = pwm;            
    }
结果:

这些人很可能是空的 您只需像这样更改代码

第一个解决方案:

您的型号:

public class Person
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string Surname { get; set; }
    public List<int> AltIDs { get; set; }
    public List<string> AltNames { get; set; }
}
public class Person
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string Surname { get; set; }
    public List<int> AltIDs { get; set; }
    public List<string> AltNames { get; set; }
}
formLoad:

private void Form1_Load(object sender, EventArgs e)
    {
        List<Person> people = new List<Person>() 
        {new Person(){ ID=1,Name="a",Surname="a",AltIDs=new List<int>(){1,2,3,4 },AltNames=new List<string>(){"a","b","c" } },
        new Person(){ ID=2,Name="b",Surname="b",AltIDs=new List<int>(){10,20,30,40 },AltNames=new List<string>(){"a","b","c" }},
        new Person(){ ID=3,Name="c",Surname="c",AltIDs=new List<int>(){100,200,300,400 },AltNames=new List<string>(){"a","b","c" }},
        new Person(){ ID=4,Name="d",Surname="d",AltIDs=new List<int>(){1000,2000,3000,4000 },AltNames=new List<string>(){"a","b","c" }},
        new Person(){ ID=3,Name="e",Surname="e",AltIDs=new List<int>(){10000,20000,30000,40000 },AltNames=new List<string>(){"a","b","c" }}
        };
        List<PersonViewModel> pwm = new List<PersonViewModel>();
        foreach (var person in people)
        {
           foreach(var id in person.AltIDs)
            {
                foreach (var name in person.AltNames)
                    pwm.Add(new PersonViewModel() { ID = person.ID, Name = person.Name, Surname = person.Surname, AltID = id, AltName = name });
            }
        }
        dgv.DataSource = pwm;

    }
FormLoad:

 private void Form1_Load(object sender, EventArgs e)
    {
        List<Person> people = new List<Person>() 
        {new Person(){ ID=1,Name="a",Surname="a",AltIDs=new List<int>(){1,2,3,4 },AltNames=new List<string>(){"a","b","c" } },
        new Person(){ ID=2,Name="b",Surname="b",AltIDs=new List<int>(){10,20,30,40 },AltNames=new List<string>(){"a","b","c" }},
        new Person(){ ID=3,Name="c",Surname="c",AltIDs=new List<int>(){100,200,300,400 },AltNames=new List<string>(){"a","b","c" }},
        new Person(){ ID=4,Name="d",Surname="d",AltIDs=new List<int>(){1000,2000,3000,4000 },AltNames=new List<string>(){"a","b","c" }},
        new Person(){ ID=3,Name="e",Surname="e",AltIDs=new List<int>(){10000,20000,30000,40000 },AltNames=new List<string>(){"a","b","c" }}
        };
        List<PersonViewModel> pwm = new List<PersonViewModel>();
        StringBuilder sbIds;
        StringBuilder sbNames;
        foreach (var person in people)
        {
            sbIds = new StringBuilder();
            sbNames = new StringBuilder();
            person.AltIDs.ForEach(c=> sbIds.Append(c.ToString()).Append(","));
            person.AltNames.ForEach(c=> sbNames.Append(c).Append(","));
            pwm.Add(new PersonViewModel() { ID = person.ID, Name = person.Name, Surname = person.Surname, AltID = sbIds.ToString().TrimEnd(','), AltName = sbNames.ToString().TrimEnd(',') });                
        }
        dgv.DataSource = pwm;            
    }
结果:

当DataGridView绑定到DataSource时,它会自动为具有基本数据类型(如int、string、double等)的属性生成列

对于作为集合的数据类型,使用DataGridViewComboxColumn。此类型的列不是自动生成的。您需要在GridView columns集合中手动添加此类列

对于您的用例,以下是解决方案

通过单击Add Column,将DataGridView添加到表单中,并从表单的designer视图手动向表单中添加列。您必须添加3个DataGridViewTextBoxColumn和2个DataGridViewComboxColumn

添加列后,这些列将如下所示

现在,在将数据源分配给DataGridView时,您需要编写以下代码。在这里,IdColumn、NameColumn和NameColumn是在上述步骤中创建列时给出的名称

dataGridView1.AutoGenerateColumns = false;
IdColumn.DataPropertyName = "ID";
NameColumn.DataPropertyName = "Name";
SurnameColumn.DataPropertyName = "Surname";
dataGridView1.DataSource = persons;
使用上述代码,您将看到集合中人员的Id、姓名和姓氏列已填充,但最后两列中的下拉列表为空

要填充下拉列表列,需要为DataGridView的CellClick事件添加事件处理程序。并在那里编写以下代码。 此处,AltIdsColumn和AltNamesColumn是在前面的步骤中手动创建时为列指定的名称

private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
    var altIdIndex = dataGridView1.Columns["AltIdsColumn"].Index;
    var altNameIndex = dataGridView1.Columns["AltNamesColumn"].Index;
    if (altIdIndex == e.ColumnIndex || altNameIndex == e.ColumnIndex)
    {
        var altIdsCell = (DataGridViewComboBoxCell)dataGridView1.Rows[e.RowIndex].Cells[altIdIndex];
        var altNamesCell = (DataGridViewComboBoxCell)dataGridView1.Rows[e.RowIndex].Cells[altNameIndex];

        if (altIdsCell.DataSource == null || altNamesCell.DataSource == null)
        {
            var person = dataGridView1.Rows[e.RowIndex].DataBoundItem as Person;
            if (person != null)
            {
                altIdsCell.DataSource = person.AltIDs;
                altNamesCell.DataSource = person.AltNames;
            }
        }
    }
}
使用此代码,当您单击各行上的下拉列表时,将填充aldid和AltNames列的下拉列表


我希望这将帮助您解决您的问题。

当DataGridView绑定到数据源时,它会自动为具有基本数据类型(如int、string、double等)的属性生成列

对于作为集合的数据类型,使用DataGridViewComboxColumn。此类型的列不是自动生成的。您需要在GridView columns集合中手动添加此类列

对于您的用例,以下是解决方案

通过单击Add Column,将DataGridView添加到表单中,并从表单的designer视图手动向表单中添加列。您必须添加3个DataGridViewTextBoxColumn和2个DataGridViewComboxColumn

添加列后,这些列将如下所示

现在,在将数据源分配给DataGridView时,您需要编写以下代码。在这里,IdColumn、NameColumn和NameColumn是在上述步骤中创建列时给出的名称

dataGridView1.AutoGenerateColumns = false;
IdColumn.DataPropertyName = "ID";
NameColumn.DataPropertyName = "Name";
SurnameColumn.DataPropertyName = "Surname";
dataGridView1.DataSource = persons;
使用上述代码,您将看到集合中人员的Id、姓名和姓氏列已填充,但最后两列中的下拉列表为空

要填充下拉列表列,需要为DataGridView的CellClick事件添加事件处理程序。并在那里编写以下代码。 此处,AltIdsColumn和AltNamesColumn是在前面的步骤中手动创建时为列指定的名称

private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
    var altIdIndex = dataGridView1.Columns["AltIdsColumn"].Index;
    var altNameIndex = dataGridView1.Columns["AltNamesColumn"].Index;
    if (altIdIndex == e.ColumnIndex || altNameIndex == e.ColumnIndex)
    {
        var altIdsCell = (DataGridViewComboBoxCell)dataGridView1.Rows[e.RowIndex].Cells[altIdIndex];
        var altNamesCell = (DataGridViewComboBoxCell)dataGridView1.Rows[e.RowIndex].Cells[altNameIndex];

        if (altIdsCell.DataSource == null || altNamesCell.DataSource == null)
        {
            var person = dataGridView1.Rows[e.RowIndex].DataBoundItem as Person;
            if (person != null)
            {
                altIdsCell.DataSource = person.AltIDs;
                altNamesCell.DataSource = person.AltNames;
            }
        }
    }
}
使用此代码,当您单击各行上的下拉列表时,将填充aldid和AltNames列的下拉列表


我希望这将帮助您解决问题。

据我所知,这是一个相当基本的“主/从”类型用户界面。在网格中,有一个带有ID、名称和姓氏的“Person”对象。显然,从您的问题来看,AltID和AltNames列表不显示在网格中

这是因为网格在尝试将“多个”值列表添加到“单个”单元格时遇到问题。正如所建议的,您可以将这些值“组合”成一个“单个”字符串并使用它。但是,这是零件的额外工作,如果编辑单元格,可能会产生更多工作

本例中的一个问题是,每个人的AltIDs列表可以并且将有不同数量的元素。一种可能的解决方案是简单地将这些作为新行添加,其中人员信息ID、姓名和姓氏是重复的。这将工作,但我不是很友好的用户。组合框选项也会起作用,但是它可能会再次让用户感到困惑,因为组合框“通常”表示用户从多个值中选择“单个”值

还可以“展平”每个person对象,并为列表中的每个AltID设置一列。这将起作用,但网格中可能存在较大的间隙。再说一次,不是很友好。这都是豆豆 我们不得不考虑另外一份名单,这让我们感到非常震惊

考虑到这一点,很明显你将不得不做额外的工作,除非你使用先进的第三方网格或在图片中添加更多的网格…在这种情况下,总共3个3。一个代表人物,另一个代表身份证,第三个代表姓名。正确安排网格可能是一个小工作,然而,有了三个网格,它将使上述所有问题…消失。此外,编码将更容易

用户可以从第一个网格中“选择”一个人,然后第二个网格列出所有AltID值,第三个网格列出所有AltName值。如果每个网格使用“相同”数据源,那么……当用户在人员网格中选择不同的人员时,AltID网格和AltName网格将“自动”更新/刷新适当的值。这也将使任何网格/值上的CRUD操作更容易

我在当前Person类中看到的唯一问题是这两个列表属于“原始”类型。使用这种方式,列表将无法正确显示,网格需要一个类。因此,您需要为AltID和AltName列表创建一个包装器类。然后更改Person类中的列表值。类似于

public class AltID_C {
  public int AltID { get; set; }
}

public class AltName_C {
  public string AltName { get; set; }
}

public class Person {
  public int ID { get; set; }
  public string Name { get; set; }
  public string Surname { get; set; }
  public List<AltID_C> AltIDs { get; set; }
  public List<AltName_C> AltNames { get; set; }
}
下面是完成示例的附加代码

private List<Person> GetRandomData(int numberOfPersons) {
  List<Person> listOPeople = new List<Person>();
  Person curPerson;
  Random rand = new Random();
  for (int i = 0; i < numberOfPersons - 1; i++) {
    curPerson = new Person() {
      ID = rand.Next(1, 1000),
      Name = "Name_" + i + 1,
      Surname = "Sname_" + i + 1,
      AltIDs = GetRandomNumberOfInts(rand),
      AltNames = GetRandomNumberOfStrings(rand)
    };
    listOPeople.Add(curPerson);
  }
  return listOPeople;
}

private List<AltID_C> GetRandomNumberOfInts(Random rand) {
  List<AltID_C> listOInts = new List<AltID_C>();
  int numberOfInts = rand.Next(0, 10);
  for (int i = 0; i < numberOfInts - 1; i++) {
    listOInts.Add(new AltID_C { AltID = rand.Next(1, 10000) });
  }
  return listOInts;
}

private List<AltName_C> GetRandomNumberOfStrings(Random rand) {
  List<AltName_C> listOStrings = new List<AltName_C>();
  int numberOfStrings = rand.Next(0, 10);
  for (int i = 0; i < numberOfStrings - 1; i++) {
    listOStrings.Add(new AltName_C { AltName = "RandString: " + rand.Next(1, 1000) });
  }
  return listOStrings;
}

希望能有所帮助。

据我所知,这是一个相当基本的“主/从”类型用户界面。在网格中,有一个带有ID、名称和姓氏的“Person”对象。显然,从您的问题来看,AltID和AltNames列表不显示在网格中

这是因为网格在尝试将“多个”值列表添加到“单个”单元格时遇到问题。正如所建议的,您可以将这些值“组合”成一个“单个”字符串并使用它。但是,这是零件的额外工作,如果编辑单元格,可能会产生更多工作

本例中的一个问题是,每个人的AltIDs列表可以并且将有不同数量的元素。一种可能的解决方案是简单地将这些作为新行添加,其中人员信息ID、姓名和姓氏是重复的。这将工作,但我不是很友好的用户。组合框选项也会起作用,但是它可能会再次让用户感到困惑,因为组合框“通常”表示用户从多个值中选择“单个”值

还可以“展平”每个person对象,并为列表中的每个AltID设置一列。这将起作用,但网格中可能存在较大的间隙。再说一次,不是很友好。事实上,我们还必须考虑另外一个名单,这一切都是加倍的

考虑到这一点,很明显你将不得不做额外的工作,除非你使用先进的第三方网格或在图片中添加更多的网格…在这种情况下,总共3个3。一个代表人物,另一个代表身份证,第三个代表姓名。正确安排网格可能是一个小工作,然而,有了三个网格,它将使上述所有问题…消失。此外,编码将更容易

用户可以从第一个网格中“选择”一个人,然后第二个网格列出所有AltID值,第三个网格列出所有AltName值。如果每个网格使用“相同”数据源,那么……当用户在人员网格中选择不同的人员时,AltID网格和AltName网格将“自动”更新/刷新适当的值。这也将使任何网格/值上的CRUD操作更容易

我在当前Person类中看到的唯一问题是这两个列表属于“原始”类型。使用这种方式,列表将无法正确显示,网格需要一个类。因此,您需要为AltID和AltName列表创建一个包装器类。然后更改Person类中的列表值。类似于

public class AltID_C {
  public int AltID { get; set; }
}

public class AltName_C {
  public string AltName { get; set; }
}

public class Person {
  public int ID { get; set; }
  public string Name { get; set; }
  public string Surname { get; set; }
  public List<AltID_C> AltIDs { get; set; }
  public List<AltName_C> AltNames { get; set; }
}
下面是完成示例的附加代码

private List<Person> GetRandomData(int numberOfPersons) {
  List<Person> listOPeople = new List<Person>();
  Person curPerson;
  Random rand = new Random();
  for (int i = 0; i < numberOfPersons - 1; i++) {
    curPerson = new Person() {
      ID = rand.Next(1, 1000),
      Name = "Name_" + i + 1,
      Surname = "Sname_" + i + 1,
      AltIDs = GetRandomNumberOfInts(rand),
      AltNames = GetRandomNumberOfStrings(rand)
    };
    listOPeople.Add(curPerson);
  }
  return listOPeople;
}

private List<AltID_C> GetRandomNumberOfInts(Random rand) {
  List<AltID_C> listOInts = new List<AltID_C>();
  int numberOfInts = rand.Next(0, 10);
  for (int i = 0; i < numberOfInts - 1; i++) {
    listOInts.Add(new AltID_C { AltID = rand.Next(1, 10000) });
  }
  return listOInts;
}

private List<AltName_C> GetRandomNumberOfStrings(Random rand) {
  List<AltName_C> listOStrings = new List<AltName_C>();
  int numberOfStrings = rand.Next(0, 10);
  for (int i = 0; i < numberOfStrings - 1; i++) {
    listOStrings.Add(new AltName_C { AltName = "RandString: " + rand.Next(1, 1000) });
  }
  return listOStrings;
}

希望这能有所帮助。

我还需要查看DataViewGrid中的列表,以及AltID和AltName。如问题中所述,我可以看到简单的属性,如int、string等,但不能看到List。在datagridview 1中显示列表有两个选项。将列表与逗号分开,并将其显示在第2行中。根据每行列表的数量,必须重复这些行更新我的代码,使用viewmodel获取简单的person模型,表单加载使用内部foreach altids、altnames并转换为简单模型以显示结果难道我们不能只在一个单元格中显示列表,并用逗号分隔,例如,如果列表有值{1、2、3、4}它应该在DataGridView的单元格中显示为1,2,3,4,列名称为AltIDsupdate代码,并添加第二种方式在一行中显示列表。我也需要在DataViewGrid中查看列表,即AltIDs和AltNames。如问题中所述,我能够看到简单的属性,如int,
字符串等,但不是列表。在datagridview 1中显示列表有两个选项。将列表与逗号分开,并将其显示在第2行中。根据每行列表的数量,必须重复这些行更新我的代码,使用viewmodel获取简单的person模型,表单加载使用内部foreach altids、altnames并转换为简单模型以显示结果难道我们不能只在一个单元格中显示列表,并用逗号分隔,例如,如果列表有值{1、2、3、4}在DataGridView的单元格中,它应显示为1,2,3,4,列名称为AltidUpdate code,并添加第二种方式以在一行中显示列表。因此,我需要使用3个网格来完成此操作,根据您的解决方案,这意味着需要3个网格,或者我没有得到要点?这是正确的,三个网格通过相同的数据源链接在一起,这将使编码变得容易。我不会否认网格的正确布局可能需要一些思考。我猜其他网格的位置取决于每个网格中有多少数据。此外,另一个关键因素是数据是否仅用于显示。如果允许用户添加、编辑或删除项目,那么使用三个网格可能会更容易。如果只用于显示,那么将项目组合成一个字符串可能是更好的方法。好的,那么您如何放置网格,我的意思是,它们会并排放置,使它们在视觉上显示为1个网格,而实际上它们是3个独立的网格?正如我所说,网格布局需要一些思考。我在左侧设置了人员网格,其他两个网格占据了人员网格垂直深度的一半…即,左侧一个网格,右侧两个网格相互堆叠。我不知道你如何安排它们看起来像一个网格,而不会遇到前面描述的可能问题。因此,我需要使用3个网格来完成这项工作,根据你的解决方案,这意味着3个网格是必要的,还是我没有理解要点?这是正确的,三个网格通过相同的数据源链接在一起,这将使编码变得容易。我不会否认网格的正确布局可能需要一些思考。我猜其他网格的位置取决于每个网格中有多少数据。此外,另一个关键因素是数据是否仅用于显示。如果允许用户添加、编辑或删除项目,那么使用三个网格可能会更容易。如果只用于显示,那么将项目组合成一个字符串可能是更好的方法。好的,那么您如何放置网格,我的意思是,它们会并排放置,使它们在视觉上显示为1个网格,而实际上它们是3个独立的网格?正如我所说,网格布局需要一些思考。我在左侧设置了人员网格,其他两个网格占据了人员网格垂直深度的一半…即,左侧一个网格,右侧两个网格相互堆叠。我不知道你如何安排它们看起来像一个网格,而不碰到前面描述的可能问题。写得好,建议也很好!Mehdi首先回答,他的答案对我来说很有帮助,所以我给了他正确的答案。再次感谢!写得好,建议也不错!Mehdi首先回答,他的答案对我来说很有帮助,所以我给了他正确的答案。再次感谢!