【问题标题】:C# timer event to update datagridviewC#定时器事件更新datagridview
【发布时间】:2020-12-03 21:15:09
【问题描述】:

我正在尝试使用文本框和 datagridview 创建一个“仪表板”表单。加载到其中的数据来自每 10 分钟更新一次的 Excel 电子表格。我添加了一个计时器来刷新数据,但无法更新表单上的文本框和 datagridview。我可以告诉计时器正在工作,因为如果我向下滚动到 datagridview 的底部,表单将会更新。我错过了什么?

        public AllOrders()
    {
        InitializeComponent();
        System.Windows.Forms.Timer timer1 = new System.Windows.Forms.Timer();
        timer1.Interval = 10000;
        timer1.Tick += new System.EventHandler(timer1_Tick);
        timer1.Enabled = true;
        timer1.Start();
        Get_Data();
    }
    private void Get_Data()
    {
        // connect to get file
        string ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source='\\\\xxxxx\\labdash.xls';Extended Properties=\"Excel 8.0;HDR=Yes\";";
        OleDbConnection MyConnection = new OleDbConnection(ConnectionString);
        // select only worksheet in spreadsheet
        OleDbDataAdapter myDataAdapter = new OleDbDataAdapter("select * from [Sheet1$]", MyConnection);
        // define dataset as entire spreadsheet
        DataSet ds = new DataSet();
        myDataAdapter.Fill(ds);
        // define view to set filters, restrictions, etc
        DataView dv;
        dv = new DataView(ds.Tables[0], "ordept = 'CHE'", "ordept", DataViewRowState.CurrentRows);
        dataGridView1.DataSource = dv;
        // define header information
        ctr = dataGridView1.Rows.Count;
        textBox1.Text = ctr.ToString() + "  outstanding tests";
        upddte = dataGridView1.Rows[1].Cells[14].Value.ToString();
        updtim = dataGridView1.Rows[1].Cells[15].Value.ToString();
        textBox2.Text = upddte.Substring(5, 2) + "  last updated";
        // hide columns not needed
        dataGridView1.Columns[0].Visible = false;
        dataGridView1.Columns[4].Visible = false;
        dataGridView1.Columns[5].Visible = false;
        dataGridView1.Columns[6].Visible = false;
        dataGridView1.Columns[9].Visible = false;
        dataGridView1.Columns[10].Visible = false;
        dataGridView1.Columns[11].Visible = false;
        dataGridView1.Columns[14].Visible = false;
        dataGridView1.Columns[15].Visible = false;
        dataGridView1.Columns[17].Visible = false;
        // sort by priority, specimen date, specimen time
        dataGridView1.Sort(dataGridView1.Columns[0], ListSortDirection.Ascending);
        dataGridView1.Sort(dataGridView1.Columns[13], ListSortDirection.Ascending);
        dataGridView1.Sort(dataGridView1.Columns[14], ListSortDirection.Ascending);
        // change font color for certain status'
        dataGridView1.RowPrePaint
            += new System.Windows.Forms.DataGridViewRowPrePaintEventHandler(dataGridView1_RowPrePaint);
        dataGridView1.Update();
        dataGridView1.Refresh();
        textBox1.Update();
        textBox1.Refresh();
        textBox2.Update();
        textBox2.Refresh();
    }
    private void timer1_Tick(object sender, EventArgs e)
    {
        Get_Data();
    }

【问题讨论】:

  • 您应该将计时器添加到表单本身。目前,您仅将其作为构造函数中的局部变量,因此它可能随时被垃圾收集器销毁。
  • 我认为从 Visual Studio 工具箱添加计时器就是将其添加到表单本身。我错了吗?

标签: c# winforms datagridview timer


【解决方案1】:

显然你的表单类被命名为AllOrders。构造函数:

public AllOrders()
{
    InitializeComponent();
    System.Windows.Forms.Timer timer1 = new System.Windows.Forms.Timer();
    ...
}

在构造函数结束时 timer1 会发生什么?有没有人持有对计时器对象的引用。垃圾收集器会做什么?

您的计时器是一个组件。您的表单可以包含许多组件,但您必须让它们保持活动状态,直到您确定不再需要它们为止。 Timer 也是 IDisposable 的,你应该在你的表单被 Deisposed 时 Dispose 它。

任何组件执行此操作的简单方法是将组件添加到您的Form.Components。查看 Form Dispose,就在 Form 的 InitializeComponent 上方。

您可以使用 Visual Studio 设计器添加计时器。它位于组件下的工具箱中。 如果要手动添加,请确保它在构造函数之后保持活动状态,并将其添加到 this.Components 中,这样您就知道它会在您的表单被释放时被释放。

class Allorders : Form
{
    private readonly Timer timer1;

    public AllOrders()
    {
        InitializeComponent();
        this.timer1 = new Timer();
        this.components.Add(this.timer1);
        ... // other timer initializations
    }
}

Dispose this.components 的代码已经在您的表单中。Dispose 根据您在表单中添加的其他控件,this.components 为空。在这种情况下,您必须自己创建它:

InitializeComponent();

if (this.components == null)
    this.components = new System.ComponentModel.Container();
this.timer1 = new Timer();
this.components.Add(this.timer1);

【讨论】:

  • 我相信我了解组件是什么(我从 Visual Studio 工具箱中添加的项目,例如文本框和计时器)。我只是不明白如果这些项目是从工具箱中添加的,我还需要做什么。我原以为它需要的所有东西都会添加到正确的位置。所以你是说我必须在代码中添加更多内容,这样它才不会在过程中的某个未知点被破坏?我在 Initialize 行之后添加了 5 个“计时器”行,因为我在另一个解决方案中看到了这些行。但他们似乎也没有让它发挥作用。
  • 确实,如果您使用工具箱添加了一个控件,那么您很少需要自己做一些事情。您可以在InitializeComponents 中看到创建的代码。您可以看到创建了一个字段以使您的组件保持活动状态直到销毁。您的错误是您忘记将计时器保存在构造函数之外。有些人喜欢通过键入代码自己添加控件。在这种情况下,您将它们作为成员或属性添加到您的类中,并在调用 InitializeComponent 后在构造函数中创建控件。不要忘记将其添加到 this.Components 以确保它已被处置
【解决方案2】:

您将在计时器的每个滴答声上添加一个绘画事件。这会调用多个绘制事件并减慢一切速度,尤其是在您滚动时。

将绘制订阅移动到构造函数。此外,在表单级别声明计时器,以便在表单关闭时正确处理它。

System.Windows.Forms.Timer timer1;

public AllOrders()
{
  InitializeComponent();
  dataGridView1.RowPrePaint += dataGridView1_RowPrePaint;

  timer1 = new System.Windows.Forms.Timer();
  timer1.Interval = 10000;
  timer1.Tick += timer1_Tick;
  timer1.Start();
}

【讨论】:

  • 好的。我从 tick 事件中删除了该过程,将绘制过程移至 INITIALIZE 下方,在其下方添加了计时器内容。屏幕上的数据仍然没有更新。即使我滚动到底部也不行。它仅在我单击“更新”按钮时更新。满足间隔时触发什么事件?如果我不告诉它,它怎么知道获取新数据并刷新屏幕?
  • @Cathy 你的timer1_tick还在打电话给Get_Data()吗?您是否在等待 10 秒以查看它是否会触发?
  • 是的,Get_Data() 的唯一调用是在表单加载和按钮单击中。我让它运行了 10 分钟。当什么都没发生时,我向下滚动查看它是否会更新。当它仍然没有时,我单击了按钮。然后它更新了。
  • @Cathy the only call for Get_Data() is in the form load and the button click. 不应该在计时器滴答声中吗?你想让计时器做什么?
  • 我在计时器滴答声中有它。你说它每次都在执行 Get_Data,所以我把它拿出来了。我想我很困惑计时器滴答的作用以及间隔的用途。计时器滴答是否意味着它每毫秒执行一次计时器滴答事件?我想我需要检查间隔的刻度数,如果相等,则执行 Get_Data()。
猜你喜欢
  • 1970-01-01
  • 2012-05-15
  • 2011-07-28
  • 2012-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-25
相关资源
最近更新 更多