当前位置:   article > 正文

c#多线程Timer定时器设计,访问主线程控件_c# timer 多线程

c# timer 多线程

        假设现在我们要实现这样一个功能:我们需要让电机某轴(或几轴)循环往复运动,并每次循环获取电机运动结束位置,记录到csv文件中,每个循环结束后(即到达起点),我们要在textBox上写入循环次数。

        我们有toPoint(axis,point,velocity),waitMotorEnd(axis,timeout);getMotorPos(axis),

killMotor(axis)

 一. 第一种方法是添加一个Timer控件,设置Interval间隔,添加tick事件,在这个事件中编程和调用其他函数,用两个按钮和几个变量控制tick是否开启和关闭。

点评:这种方法简单易行,它可以访问任何控件,但是主线程已经有一个timer控件实时读取电机位置并显示出来,导致主界面在电机运动期间是卡死状态,包括最小化等界面图标均无法选中,因为这个timer控件本质上是主线程上的

二. 通过 system.Timers使用系统timer,这种方法不用在界面上拖拽控件,相应的需要在代码中设置属性。

        首先我们先考虑主循环的事件处理,然后再考虑主线程控件调用问题,因为是线程安全的,这个线程是不能直接读取主线程中的控件,需要启用委托。

代码简单如下,仔细弄明白以便在自己的代码中进行移植。

 

  1. using Systems.Timers;
  2. using System.Threading;
  3. namespace demo_np
  4. {
  5. public partial class MainForm : Form
  6. {
  7. private int count_cycle=0; //循环次数要填入textBox中,全局变量。
  8. private string path = @"D:\MOTOR_CSV\info.csv";//写入csv的目录,文件在代码中建立。
  9. public MainForm()
  10. {
  11. InitializeComponent();
  12. }
  13. private void Form1_Load(object sender, EventArgs e)
  14. {
  15. InitTimer(); //这个是我们设置的timer属性初始化函数。
  16. }
  17. System.Timers.Timer timer;//实例化一个计时器
  18. private void InitTimer()
  19. {
  20. //设置定时间隔,本例较大,因为太小的话代码执行太快,电机还没动起来导致程序总是认为你电机已经循环过。
  21. int interval = 2000;
  22. timer = new System.Timers.Timer(interval);
  23. //设置执行一次(false)还是一直执行(true)
  24. timer.AutoReset = true;
  25. timer.Enabled = false;
  26. //绑定Elapsed事件,让计时器能够不断执行这个TimerCycle事件
  27. timer.Elapsed += new System.Timers.ElapsedEventHandler(TimerCycle);
  28. }
  29. private void TimerCycle(object sender, System.Timers.ElapsedEventArgs e)
  30. {
  31. try
  32. {
  33. timer.Enabled = false;//这里先关闭计时器,事件结尾再打开
  34. int timeout = 1000000;
  35. waitMotorEnd(0,timeout);代表0
  36. write_csv();
  37. toPoint(0,100.0f);
  38. toPoint(0,0.0f);//代表一个往复循环
  39. count_cycle = (count_cycle + 1) % 1000000;
  40. //text_count.Text=count_cycle.ToString();非法调用主线程控件。
  41. timer.Enabled = true;
  42. }
  43. catch(Exception ex)
  44. {
  45. MessageBox.Show(ex.Message, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
  46. System.Diagnostics.Debug.WriteLine(ex.Message);
  47. }
  48. //接下来是按钮控制开关及写入csv方法
  49. private void btnCycleStart_Click(object sender, EventArgs e)
  50. {
  51. count_cycle=0;
  52. timer.Enabled = true;
  53. if (!File.Exists(path))
  54. File.Create(path).Close();//创建csv文件。
  55. }
  56. private void button10_Click(object sender, EventArgs e)
  57. {
  58. killMotor(0);
  59. timer.Enabled = false;
  60. }
  61. private void write_csv()
  62. {
  63. StreamWriter sw = new StreamWriter(path, true, Encoding.UTF8);
  64. sw.Write("\r\n");
  65. sw.Write(String.Format("{0:0.0000}", getMotorPos(0) + ",");
  66. sw.Write(String.Format("{0:0.0000}", getMotorPos(0)) + ",");
  67. sw.Flush();
  68. sw.Close();
  69. }
  70. }
  71. }

上述代码非法调用控件,接下来通过委托实现访问,注意和上面代码对照需要加到哪里?

  1. delegate void text_countDelegate();
  2. private void text_count()
  3. {
  4. this.text_count.Text = cycle_count.ToString();
  5. }
  6. //这里只是定义了这个委托,名字叫text_countDelegate,既没有运行也没有和咱们这个textcount事件联系起来,那怎么办呢?

 textBox4.Invoke((txb4countDelegate)txb4count);

我们需要将这行代码加到TimerCycle非法调用那里,就可以成功访问啦

 上面这种多线程访问控件的方法好处是可以选择加参数,但是这个例子中并没有参数传递,c#给了我们这样一种方法,MethodInvoker,表示一个委托,该委托可以执行托管代码中(声明为void且不接受任何参数的)任何方法!

  1. this.Invoke((MethodInvoker)delegate
  2. {
  3. textCount.Text=cycle_count.ToString();
  4. }

欢迎任何评论,有不当的地方欢迎提出来,共同交流共同进步!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/436554
推荐阅读
相关标签
  

闽ICP备14008679号