【问题标题】:Object data not showing in DataGridView after binding绑定后对象数据未显示在 DataGridView 中
【发布时间】:2020-07-20 09:14:42
【问题描述】:

初学者!我试图仅将对象中的某些数据显示到数据网格视图中,但在 Winforms 中运行后我什么也没有得到。有什么方法可以成功实现这个或任何替代方案?

我试图遵循模板here,但尝试不成功

// Object
public class Student
    {
        public string StudentNumber { get; set; }
        public string StudentName { get; set; }
        public string StudentNameChinese { get; set; }
        public string StudentNameShort { get; set; }
        public string Gender { get; set; }
        public string IdPlaceDescription { get; set; }
        public string MobileNumber { get; set; }
        public string Major { get; set; }
        public string RoomNumber { get; set; }
        public string CheckInDate { get; set; }
        public string CheckOutDate { get; set; }
        public string RoomNoBefore { get; set; }
        public string ChangeDate { get; set; }
        public DateTime BirthDate { get; set; }
        public string Province { get; set; }
        public string Email { get; set; }
        public string OtherEmail { get; set; }
        public byte[] ProfileImage { get; set; }
    }

在表单类中

private void StudentsForm_Load(object sender, EventArgs e)
        {
            BindDataToDataGrid();
        }
// Get data from the database into a Student object class
        public Collection<Student> GetData()
        {
            // Initialize collection of students
            var collection = new Collection<Student>();

            // string sqlQuery = "select * from ProfileTable";
            string sqlQuery = "select StudentNo, StudentName, StudentNameChinese, " +
                "StudentNameShort, Gender, IdPlaceDesc, MobileNo, MajorDesc, RoomNo," +
                "CheckInDate, CheckOutDate, RoomNoBefore, ChangeDate, BirthDate," +
                "ProvinceDesc, Email, OtherEmail, Image from ProfileTable";
            using (SqlCommand command = new SqlCommand(sqlQuery, connection))
            {
                connection.Open();
                using (var reader = command.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        // Update student variables with values from ProfileTable column
                        Student student = new Student
                        {
                            StudentNumber = (string)reader["StudentNo"],
                            StudentName = (string)reader["StudentName"],
                            StudentNameChinese = (string)reader["StudentNameChinese"],
                            StudentNameShort = (string)reader["StudentNameShort"],
                            Gender = (string)reader["Gender"],
                            IdPlaceDescription = (string)reader["IdPlaceDesc"],
                            MobileNumber = (string)reader["MobileNo"],
                            Major = (string)reader["MajorDesc"],
                            RoomNumber = (string)reader["RoomNo"],
                            CheckInDate = (string)reader["CheckInDate"],
                            CheckOutDate = (string)reader["CheckOutDate"],
                            RoomNoBefore = (string)reader["RoomNoBefore"],
                            ChangeDate = (string)reader["ChangeDate"],
                            BirthDate = (DateTime)reader["BirthDate"],
                            Province = (string)reader["ProvinceDesc"],
                            Email = (string)reader["Email"],
                            OtherEmail = (string)reader["OtherEmail"],
                            ProfileImage = (byte[])reader["Image"]
                        };

                        // Add student to collection
                        collection.Add(student);
                    }
                }
                connection.Close();
            }
            return collection;
        }

编辑:下面是我只想在我的数据网格视图中看到的内容,因此我要避免只使用与数据库中的内容完全相同的数据表 p>

// Bind data from collections to datagrid columns
        void BindDataToDataGrid()
        {
            var students = GetData();
            var bind = from student in students
                       select new
                       {
                           // Values are assigned to Datagrid columns
                           studentNumber = student.StudentNumber,
                           nameShort = student.StudentNameShort,
                           room = student.RoomNumber,
                           gender = student.Gender,
                           major = student.Major,
                           number = student.MobileNumber,
                           email = student.Email,
                           profile = student.ProfileImage
                       };
            dataGridViewStudents.DataSource = bind;
        }

winforms

运行后的结果

这是数据库中的数据表的样子

【问题讨论】:

  • StudentsForm_Load 有时为时过早。尝试显示..
  • 试过了,但没有改变。早些时候直接从数据库绑定,一切正常。所以问题可能在于学生对象与 datagridview 的绑定
  • 你需要安装和使用Dapper

标签: c# winforms datagridview


【解决方案1】:

改变这个:

dataGridViewStudents.DataSource = bind;

到这里:

dataGridViewStudents.DataSource = bind.ToArray();

是的;您不能将 LINQ 查询的输出绑定到网格,但如果将其转换为数组或列表等,则可以


TBH,我可能会早点让我的生活更轻松。您编写的所有代码或多或少都可以用以下 4 行替换:

using (SqlDataAdapter da = new SqlDataAdapter (sqlQuery, connection))
{
  DataTable dt = new DataTable();
  da.Fill(dt);
  datagridViewWhatever.DataSource = dt;
}

或者安装Dapper,这个设备会接收你的查询和你的Student类,并从db中填充一个Student列表。这是您的代码的 2 行 Dapper 变体的样子:

using(var c = new SqlConnection(connstr))
  datagridViewWhatever.DataSource = (await c.QueryAsync<Student>(sqlQuery)).ToList();

是的..所有这些数百行 while(reader.Read()) .. (cast)reader["this"] .. (cast)reader["that"] 代码你都在苦苦挣扎*.. 嗖!走了!由 Dapper 自动查看查询输出的名称和对象的属性名称,然后将它们自动连接在一起(注意:将它们命名为相同,例如使查询 SELECT MobileNo as MobileNumber ... 或重命名 C# 属性)。 http://dapper-tutorial.net

*这应该是一种惩罚,就像下课后为口香糖写台词..


编辑;

您已经标记了一个补充问题,即为什么您的网格显示太多列 - 这确实应该是一个新问题,但您的网格(可能)显示的比您预期的要多,因为 AutoGenerateColumns 是真的,所以网格正在找到它的所有内容可以为其显示和添加列(绑定到的对象的每个属性一列)。要解决这个问题,您可以:

  • 关闭自动生成列并手动构建一个列集合,即您想要的列
  • 开启自动生成列,绑定网格,然后通过列删除不需要的列
  • 开启自动生成并提供属性较少的绑定对象
  • 上述的混合体

【讨论】:

  • 感谢我的计划是不在我的数据网格视图中显示数据表的副本,而只是显示从对象中选择的某些成员变量。请参阅我的问题中的最后一个代码 sn-p
  • 很多可以剪掉的地方;最简单的方法是在使用 dapper 或 dataadapter 时不将列包含在 SQL 中,这是最明智的方法,因为它不会下载不需要的数据。您还可以下载所有数据并通过从表中删除列将其丢弃,或者通过设计您的 datagridview 列集合而不只是将其保留为 AutogenerateColumns = true 来隐藏它,或者您可以自动生成它们,然后在完成后将它们删除.一切都需要设计;我们永远不能对自动流程和结果抱怨
  • 总之,用我的脚注,我试图为你节省几个小时编写最乏味、最容易出错的代码。您已经在其他地方这样做了(即使您可以手动编写 UI,也不会手动编写 UI;您使用了表单设计器,它在 FormX.Designer.cs 中编写了大量繁琐的代码)所以为什么不使用软件(Dapper)像其他软件(Forms Designer)一样编写无聊的代码(数据阅读器等等)编写无聊的代码(ui布局代码)。我回答了你的“为什么我的数据网格是空白的?”顶部查询; “因为你忘记了 ToArray()”LINQ。剩下的只是“顺便说一句”的建议
  • PPS:我和至少其他人都将您的查询理解为“为什么我的网格没有显示行?”,而不是“为什么我的网格显示太多列?” - 他们是不同的问题;你需要决定你要问的是什么;诱饵 n 开关/移动球门柱会让人心烦意乱。您可能需要稍后再问一个问题,而不是尝试在这个问题中问两个问题
  • 我完全明白你写的东西,会清理我的代码,并实施上面的建议。感谢您提供代码提示。并添加.ToArray(); 工作
【解决方案2】:

如果您将var bind 替换为您实际尝试分配给DataSource 的数据类型,您会立即找到问题的根源。 (提示:如果您没有看到错误,请使用您的调试器查看bind 的类型)

将学生放入一个 BindingList

创建一个BindingList&lt;Student&gt;,并将获取的Students放入这个BindingList:

ICollection<Student> fetchedStudents = this.GetData();
BindingList<Student> bindingStudents = new BindingList<Student>(fetchedStudents.ToList():

this.DataGridView.DataSource = bindingStudents;

小提示:如果要对学生进行排序,只需单击 DataGridView 的列标题,如果要在编辑 DataGridView 的任何单元格时自动更新,请考虑使用Nuget BindingListView

var students = ...
BindingListView<Student> view = new BindingListView<Student>(students.ToList());
dataGridView1.DataSource = view;

然后转眼!如果操作员单击列标题,您将获得自动排序。

另一个特点是容易过滤。如果您(暂时)只想显示年长的学生:

view.ApplyFilter( student => student.BirthDay.Year < 2000);

所有学生仍在视图中,如果您删除过滤器,他们将再次可见。

效率提升

GetData返回一个Collection有点浪费。假设调用者只想知道是否有任何学生,或者他只想要第一个学生:

var firstStudent = GetData().FirstOrDefault();

如果将所有学生都放在一个集合中会很可惜。

考虑以下几点:

public IEnumerable<Student> GetStudents()
{
    const string sqlQuery = "select ...";

    using (SqlCommand command = new SqlCommand(sqlQuery, connection))
    {
        connection.Open();
        using (var reader = command.ExecuteReader())
        {
            while (reader.Read())
            {
                Student student = new Student
                {
                    ...
                };
                yield return Student();       //  <=== 
            }
        }
    }
}

用法:

var firstFiveStudents = this.GetStudents().Take(5).ToList();

这不会创建包含所有学生的集合,while (reader.Read()) 会执行 5 次。

【讨论】:

  • 感谢您的方法并实现了绑定列表。我想要做的不是显示数据库表的副本,而是只显示映射到自定义数据网格视图的特定列。调试时,IEnumerable bind 变量在“结果视图”下显示列表,但执行后 Datagrid 仍然没有显示任何内容
  • 一个IEnumerable&lt;...&gt;不代表s序列的相似项,它代表potential to get a sequence of similar items。我以为你是新人,因此我没有这么说:当你将获取的数据放入列表或数组时,你的问题就解决了。可以看到我在BindingList的构造函数中调用了ToList()
  • 哦,太好了。谢谢您的帮助。将查找更多数据类型
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-07
相关资源
最近更新 更多