【问题标题】:How to add new record without losing existing record in datagridview c# winforms app如何在datagridview c#winforms app中添加新记录而不丢失现有记录
【发布时间】:2022-01-04 13:52:56
【问题描述】:

我正在使用 sql server 数据库在 c#.net 中开发一个简单的 winform 应用程序。我的申请是关于题库的。我想从这个题库创建试卷。一切正常,但问题是当我从选定的主题和章节添加随机问题时,它会完美地加载到 datagridview 中,但是当我想从第 2 章或第 3 章等添加问题时,以前的记录会被清除,新数据会添加到网格中。我想添加新记录而不会丢失在 datagridview 中加载的先前记录。任何人都可以在这个问题上帮助我吗?

 DataTable t = new DataTable();
                SqlCommand cmd = new SqlCommand($"select top {QuestionsNumericUpDown.Value} *from DescriptiveQuestions where Difficulty_Level='{DiffComboBox.Text}' and Chapter='{ChapterComboBox.Text}' and Course='{CourseComboBox.Text}' order by newid()", c);
                c.Open();
                t.Load(cmd.ExecuteReader());
                c.Close();
                DescriptiveGrid.DataSource = t;

【问题讨论】:

  • 在我的小测试中...您遇到的问题是因为每次调用代码时代码都会“创建”一个新的DataTable...不要那样做...将DataTable t = new DataTable(); 设置为“全局变量。”然后每次调用上述代码...减去DataTable t = new DataTable(); 代码行...然后这应该将查询结果“添加”到现有表t。此外,如果您在此代码之外全局设置,则无需执行该行...DescriptiveGrid.DataSource = t;...。你应该只需要设置一次。
  • 我会尽力让你知道

标签: winforms data-binding datagridview


【解决方案1】:

您的问题是,因为您将数据源与显示的数据混合在一起。

MVVM:将数据处理与显示方式分开

在现代编程中,倾向于将数据及其操作(= 模型)与其显示方式(= 视图)分开。这样做的好处是您可以将模型重用于完全不同的视图。例如,您可以在图表中显示数据。同样,您可以将视图重用于其他类似数据。

在没有任何显示类的情况下对数据处理进行单元测试也更容易:您不需要表单来测试数据。最后:虽然还没有真正的数据,但您可以使用模拟数据来测试视图。

我们需要一个特殊的适配器类来将模型附加到视图:ViewModel 类。这三个类一起缩写为 MVVM。考虑阅读一些关于此的背景信息。

回到你的问题

假设您已从表单中删除数据,并将其放入单独的类中。这个类知道如何以及在哪里获取数据、如何更新数据、在哪里存储数据、如何添加新元素等。

您的应用程序需要显示问题。也许还有一些答案?此处未处理,但在您将模型与视图分离后,您可以添加答案,而不会干扰您当前的视图。

方法可能是这样的:

interface IQuestionBank
{
    IEnumerable<Question> GetQuestions(...);
    void AddQuestion(Question question);
}

具体的界面在这里并不重要,你似乎有章节和主题的概念,可能还有随机问题。调整您的界面,使您的表单可以获取必须显示的信息。

在您的表单中,您决定要在 DataGridView 中显示获取的数据。使用 Visual Studio 设计器,您添加了 DataGridView 和列。在构造函数中,您决定哪一列应该显示哪个 Question 属性:

public MyForm()
{
    InitializeComponent();

    // which column shows which property
    this.columnQuestionId.DataPropertyName = nameof(Question.Id);
    this.columnQuestionText.DataPropertyName = nameof(Question.Text);
    this.columnQuestionDate.DataPropertyname = nameof(Question.Date);
    ...
}

// the Model is outside the form:
private IQuestionBank QuestionBank {get; } = ...

根据表单的其他几个属性(章节、主题?考官?学生姓名?),表单有一个程序可以从 QuestionBank 中获取必须显示的问题。

private IEnumerable<Question> FetchQuestionsToDisplay(...)
{
    this.QuestionBank. ... // TODO implement out of scope of this question
}

要显示问题,您需要做的就是获取它们,并将它们添加到 DataGridView 的 DataSource 中

this.DataGridView1.DataSource = this.FetchQuestionsToDisplay(...).ToList();

虽然这会显示问题,但不会记录操作员所做的更改。如果您想允许操作员更改显示的信息、编辑某些单元格、添加新问题或删除问题,您需要将问题放在 BindingList 中:

private BindingList<Question> DisplayedQuestions
{
    get => (BindingList<Question>)this.DataGridView1.DataSource;
    set => this.DataGridView1.DataSource = value;
}

操作者编辑完问题,添加了一些问题,删除了几个问题后,他通过点击确定按钮表示他已经完成了编辑:

private void OnButtonOk_Clicked(object sender, ...)
{
    // fetch the displayed questions:
    ICollection<Question> displayedQuestions = this.DisplayedQuestions;

    // Find out which Questions are changed and process them:
    this.ProcessQuestions(displayedQuestions);
}

过了一会儿,显示了一些问题,您想显示更多问题。您的问题是原始问题已被删除。因为我们将 Model 从 View 中分离出来,所以很容易在 View 中添加更多 Questions。

private IEnumerable<Question> FetchAdditionalQuestions(...)
{
    // fetch the additional questions that must be displayed.
    // out of scope of this question
    ...
}

private void ShowAdditionalQuestions()
{
    IEnumerable<Question> originalQuestions = this.DisplayedQuestions;
    IEnumerable<Question> additionalQuestions = this.FetchAdditionalQuestions();
    IEnumerable<Question> allQuestions = originalQuestions.Concate(additionalQuestions);

    this.DisplayedQuestions = new BindingList<Question>(allQuestions.ToList());
}

我创建了一个新的 BindingList。或者,您可以将附加问题一一添加到具有原始问题的 BindingList 中。不确定哪种方法更好。

其他一些有用的方法

由于您将模型与视图分开,因此很容易获得选定的问题:

private Question CurrentQuestion => (Question)this.DataGridView1.CurrentRow.DataBoundItem;

private IEnumerable<Question> SelectedQuestions =>
    this.DataGridView1.SelectedRows
        .Cast<DataGridViewRow>()
        .Select(row => row.DataBoundItem)
        .Cast<Question>();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-21
    • 2022-01-06
    • 1970-01-01
    • 1970-01-01
    • 2016-08-02
    • 1970-01-01
    • 2023-01-12
    相关资源
    最近更新 更多