【问题标题】:How can i read cell value in C# from DataGridView如何从 DataGridView 读取 C# 中的单元格值
【发布时间】:2021-03-27 02:55:33
【问题描述】:

我正在尝试为学校作业做一个 StackAutomata,我尝试通过 for 找到单元格,但他们无法读取它 int i、K 和 J 在 do {} while cicle 之外创建

for (int j = 0; j < gv1.Columns.Count; j++)
                {
                    if (input[i].ToString() == gv1.Rows[0].Cells[j].Value)
                    {
                        K = j;
                    }
                }

                J = K;
                


string a = verem.Pop();
for (int j = 0; j < gv1.Rows.Count; j++)
                    {
                        if (a == gv1.Rows[j].Cells[0].Value)
                        {
                            K = j;
                        }
                    }

我错过了什么?

【问题讨论】:

  • 也许你需要强制转换为 int,因为单元格值是 object 类型的。

标签: c# winforms datagridview stack


【解决方案1】:

自己直接读写 DataGridView 很少是个好主意。最好将模型与模型的显示方式分开。

如果您的数据可以在没有显示的情况下存在,那么更改显示方式会更容易,在另一个控件或不同格式中重用数据会更容易。更容易对数据处理进行单元测试(无需表单!),更改数据的内部布局,而无需更改显示此数据的人员。

View 和 Model 之间的这种分离是在 MVVM 模型中以极值方式实现的,但 windows Forms 也通过 Data Binding 支持这一点。

只要你有一个控件可以显示一系列相似项的信息,无论是 ListBox、DataGridView 还是 GraphView,你都会发现它有一个属性DataSource

您所要做的就是将要显示的数据放入数据源中。其他属性定义必须如何显示 DataSource 中的数据。如果操作员改变了显示的数据,那么原始数据会自动更新。

假设您的 DataGridView 必须显示一组客户:每行一个客户。

您的 DataGridView 有多个 DataGridViewColumns。每列将显示其中一个属性的值。要显示的属性名称在属性DataGridViewColumn.DataPropertyName 中。

您所要做的就是制作一系列相似的项目,并将其分配给 DataGridView.DataSource。

举个例子会有所帮助。

假设您需要展示一系列学生:

class Customer
{
    public int Id {get; set;}
    public string Name {get; set;}
    public DateTime BirthDay {get; set;}
    ...
}

您希望在列中显示这三个学生属性。使用 Visual Studio 设计器添加列并分配 DataPropertyName。结果可以在InitializeComponents找到,也可以自己动手:

private readonly DataGridViewColumn columnId = new DataGridViewColumn();
private readonly DataGridViewColumn columnName = new DataGridViewColumn();
private readonly DataGridViewColumn columnBirthDay = new DataGridViewColumn();

// constructor
public MyForm()
{
    InitializeComponents();

    // define which column should display which Student property
    this.columnId.DataPropertyName = nameof(Student.Id);
    this.columnName.DataPropertyName = nameof(Student.Name);
    this.columnBirthDay.DataPropertyName = nameof(Student.BirthDay);

    // the the DataGridView to use these columns:
    this.dataGridView1.Columns.Add(this.columnId);
    this.dataGridView1.Columns.Add(this.columnName);
    this.dataGridView1.Columns.Add(this.columnBirthday);
}

通常您设置其他列属性:设置标题的文本、列顺序,有时您定义显示格式,例如:对于生日,您不想显示一天中的时间。但是,如果您愿意,您可以将列 ID 设为只读,使用粗体等。

请注意,到目前为止,我们在没有一个实际学生的情况下完成了所有工作。

如果你想显示Students但不想编辑它们,将它们放在一个Collection中并将这个集合分配给DataGridView的DataSource就足够了

List<Student> students = ...
this.DataGridView1.DataSource = students;

但是,如果您希望操作员可以添加/删除/更改/重新排序学生,您需要一种机制来更新学生集合中的更改。如果您将数据放入 BindingList

,则会自动完成此操作
IList<Student> students = ...
BindingList<Student> displayedStudents = new BindingList<Student>(students);
this.DataGridView1.DataSource = displayedStudents;

显示所有学生。操作员可以根据需要添加/删除/更改学生(除了您只读的列)。所有更改都会在 BindingList 中自动更新。

您可以从 BndingList 订阅事件以对这些更改做出反应,但更常见的情况是您什么都不做,直到操作员告诉您他完成更改,例如按下按钮:

private void ButtonOk_Clicked(object sender, ...)
{
    DataGridView dataGridView = (DataGridView)sender;
    BindingList<Student> students = (BindingList<Student>)dataGridView.DataSource;

    foreach (Student student in students)
    {
         this.ProcessStudent(student);
    }

如果您保存了原始学生的副本,您可以检测哪些学生被更改、添加、删除并决定如何处理它们。 如果您需要对选定的行执行某些操作:

IEnumerable<Student> selectedStudents = this.dataGridView1.SelectedRows
    .Cast<DataGridViewRow>()
    .Select(row => row.DataBoundItem)
    .Cast<Student>();

一个不错的功能:假设您希望您的软件分配学生的 ID,而不是操作员。然后,每当操作员想要添加新行时,您都必须使用唯一的 Id 创建学生。这是通过处理事件BindingList.AddingNew

来完成的
private void StudentCollection_AddingNew(object sender, AddingNewEventArgs e)
{
    // You need to make a Student with a unique Id:
    int newStudentId = this.CreateUniqueStudentId();
    e.NewObject = new Student
    {
        Id = newStudentId,
        // the operator has to fill in the rest of the properties
    }
}

您是否注意到您不必关心学生的显示方式:您不必关心哪些属性、什么显示格式或列顺序。如果将来有人决定不再显示学生的生日,或重新排列列,可能会更改以大写字母显示学生的姓名:所有这些方法仍然有效。

【讨论】:

    【解决方案2】:
    for (int j = 0; j < gv1.Columns.Count; j++) {
      if (input[i].ToString() == gv1.Rows[0].Cells[j].Value.ToString()) {
        K = j;
      }
    }
    
    J = K;
    
    string a = verem.Pop();
    for (int j = 0; j < gv1.Rows.Count; j++) {
      if (a == gv1.Rows[j].Cells[0].Value.ToString()) {
        K = j;
      }
    }
    

    您不能将gridview.Rows.Cells.Value 与字符串进行比较,因为它是Object,只需添加.ToString() 方法即可。

    另外,请为您的变量找到一个更好的名称,这会使您的代码更具可读性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-05
      • 1970-01-01
      • 1970-01-01
      • 2012-01-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多