带有线程的定时器的想法c#窗口窗体

本文关键字:窗口 窗体 定时器 线程 | 更新日期: 2023-09-27 18:16:49

我的项目有一个MainForm,我显示F_Insert并为MainForm设置MdiParent

F_Insert f = new F_Insert();
f.MdiParent = this;  
f.Show();

在F_Insert中,我放置了一个带有CLick事件的按钮,像这样

 private void btn_Add_Click(object sender, EventArgs e)
 {
       //Insert data to SQL
 }

此外,我想自动上传从F_Insert插入的数据每5秒

我使用System.Timer.Timer并在MainForm_Load中将其设置为Thread

Thread t1 = new Thread(new ThreadStart(Timerss)); //In MainFormLoad event
t1.Start(); 
public void Timerss()
    {
        System.Timers.Timer timer = new System.Timers.Timer(5000);
        timer.Elapsed += Timer_Insert_Tick;
        timer.AutoReset = true;
        timer.Start();
    }
private static void Timer_Insert_Tick(object sender, System.Timers.ElapsedEventArgs e)
    {
      //code auto upload data to server here
      //Data get from Sql Local to upload SQL in Server
    }

问题是它不能正常工作。我觉得当我插入数据表单F_Insert时,数据受到我在MainForm load中启动的Timerss线程的影响。

向您展示我的问题的简单方法:当我拆分两个工作(插入并上传)到2个不同的工作,它工作得很好,这意味着我插入数据完整,然后,我上传数据,它将工作良好。但当我插入数据和数据自动上传定时器在同一时间,我看到一些错误:连接SQL关闭或打开错误,没有数据得到从F_Insert,有时它得到重复的数据(旧数据)

对于这个问题,请给我提一些建议。对不起,我是新手在线程。谢谢!!

带有线程的定时器的想法c#窗口窗体

根据你想做的事情,应该修改这段代码,但我希望它能给你一个工作的起点。

首先让我们创建静态字段:

static volatile bool isDataChanged;

关键字volatile使这个bool线程安全,这意味着当它被多线程环境中的任何线程访问时,这个字段总是保存最新的(因此是正确的)值。

我们需要这个字段保存bool值,稍后用于检查数据是否被修改。

假设数据在click事件处理程序中被修改,我们应该将这个标志设置为true:

 private void btn_Add_Click(object sender, EventArgs e)
 {
       // Data is modified in UI thread
       isDataChanged = true;
 }

然后让我们假设在Timer tick事件中,我们应该将最新的数据上传到数据库(数据位于UI线程中,并且可能在两个tick事件之间的时间跨度中发生变化)。

首先我们检查我们的数据是否有任何变化,如果没有,我们就退出方法。如果做了改变,我们需要将它们上传到数据库,为了做到这一点,我们必须处理这样一个事实,即定时器线程中的数据很可能与UI线程中的数据不一样。

让我们创建本地变量来保存我们从UI线程中获取的正确数据,并使用this.Invoke()来调用UI线程上的Func<object>委托。附加到委托的方法返回从UI线程检索到的正确数据的实例作为object。我们显式地将其强制转换为数据的类型(通常是List<T>Dictionary<T1, T2>这样的集合类型之一),并使用此数据将其上传到DB。

之后,由于我们在DB中的数据是正确的,我们将标志isDataChanged更改为false

private void Timer_Insert_Tick(object sender, System.Timers.ElapsedEventArgs e)
{
   if(!isDataChanged) return;
   // A very important line. It gets data from UI thread before uploading it
   // Change DataType with your data Type and dataToUpload with data instance
   DataType data = (DataType)this.Invoke(new Func<object>(() => dataToUpload));
   //use data to upload your data to server
   isDataChanged = false;
}

注:此外,最好将对定时器的引用置于外部作用域中(因此它可以从表单中的任何地方访问)

public partial class MyForm : Form
{
   ...
   System.Timers.Timer timer; 
   public void Timerss()
   {
      timer = new System.Timers.Timer(5000); 
   }
   ...
}