C# Windows窗体应用程序自动执行(2021.6.4)

Posted jing_zhong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C# Windows窗体应用程序自动执行(2021.6.4)相关的知识,希望对你有一定的参考价值。

前提环境(已安装VS2015+C#)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1、三种方式

        在C#Windows窗体应用程序开发的过程中,窗体中有 button按钮控件 、 textbox文本框控件 、 checkbox选择框控件 、 treeview树形视图控件等 ,在这些控件的事件函数中可以编写自己的目标代码以实现特定的功能,但往往有时随着应用开发规模的扩大(控件的增多),我们希望一键式操作通过一个按钮来触发其他控件的事件进而按照设计好的流程自动执行对应的功能,从而实现整个流程自动化执行的效果。

1.1 使用工具箱中的定时器Timer

        在 Windows 窗体应用程序中,定时器控件 Timer 与其他的控件略有不同,它并不直接显示在窗体上,而是与其他控件连用,表示每隔一段时间执行一次 Tick 事件。定时器控件中常用的属性是 Interval,用于设置时间间隔,以毫秒为单位。此外,在使用定时器控件时还会用到启动定时器的方法(Start)、停止定时器的方法(Stop)。
在这里插入图片描述
在这里插入图片描述
        在C# Windows窗体应用程序中,Visual Studio左侧的工具箱可以找到Timer控件,它的作用就是按照用户定义的间隔引发事件使用方法:1、首先用一个整型变量 i 来存储计划所用的时间;2、然后需要在Timer控件的Tick事件中编写让该控件在计时过程中要执行的操作以及满足预期条件后停止计时的代码;3、同时在触发计时器定时开始的代码中设定定时器开始启动和它的间隔时间

int i;
private void run1()
{
    i = 0;
    this.timer1.Interval = 1000;//设置time1的间隔时间
    this.timer1.Start();//定时器开始计时
}
private void timer1_Tick(object sender, EventArgs e)
{
    i++;
    if (i >= 5)//if条件里加入判断代码,这里设置5s后停止 
    { 
    	this.timer1.Stop();//定时器停止计时
    }
    this.textBox1.Text = "Hello!" + i.ToString();//计时器在停止之前计时过程中要执行的操作,这里让文本框随时间动态显示文本
    this.textBox2.Text = "World!" + i.ToString();
}

private void button1_Click(object sender, EventArgs e)//点击button1触发定时器方法run()
{
    run1();
}

1.2 新建线程调用委托方法

        新建线程调用委托方法本质上也是一个多线程的方法,
        线程Thread被定义为程序的执行路径。每个线程都定义了一个独特的控制流。如果您的应用程序涉及到复杂的和耗时的操作,那么设置不同的线程执行路径往往是有益的,每个线程执行特定的工作。线程是轻量级进程。一个使用线程的常见实例是现代操作系统中并行编程的实现。使用线程节省了 CPU 周期的浪费,同时提高了应用程序的效率。线程生命周期开始于 System.Threading.Thread 类的对象被创建时,结束于线程被终止或完成执行时。
        在 C# 中,System.Threading.Thread 类用于线程的工作。它允许创建并访问多线程应用程序中的单个线程。进程中第一个被执行的线程称为主线程。当 C# 程序开始执行时,主线程自动创建。使用 Thread 类创建的线程被主线程的子线程调用。下面列出了线程生命周期中的各种状态:

  1. 未启动状态:当线程实例被创建但 Start 方法未被调用时的状况。
  2. 就绪状态:当线程准备好运行并等待 CPU 周期时的状况。
  3. 不可运行状态:下面的几种情况下线程是不可运行的:
    3.1 已经调用 Sleep 方法
    3.2 已经调用 Wait 方法
    3.3 通过 I/O 操作阻塞
  4. 死亡状态:当线程已完成执行或已中止时的状况。

        C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针。委托(Delegate) 是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。委托(Delegate)特别用于实现事件和回调方法。所有的委托(Delegate)都派生自 System.Delegate 类。委托声明决定了可由该委托引用的方法。委托可指向一个与其具有相同标签的方法。一旦声明了委托类型,委托对象必须使用 new 关键字来创建,且与一个特定的方法有关。当创建委托时,传递到 new 语句的参数就像方法调用一样书写,但是不带有参数。

using System.Threading;

delegate void set_Text(string s);//定义文本框委托
set_Text Set_Text;//定义一个委托实例对象

private void setTextbox1Text(string s)//通过字符串来改变textbox1值的自定义方法
{
    this.textBox1.Text = s;
}

private void setTextbox2Text(string s)//通过字符串来改变textbox2值的自定义方法
{
    this.textBox2.Text = s;
}

private void run2_withouteventparameter()//不带事件参数
{
     //前5秒动态改变textbox1的值
     Set_Text = new set_Text(setTextbox1Text);//实例化
     for (i=0;i<5;i++)
     {
         this.textBox1.Invoke(Set_Text, new object[] { "Hello_"+i.ToString() });//通过调用委托来改变textbox1的值
         Thread.Sleep(1000);//线程休眠1s,隔一秒再执行
     }
     //后5秒动态改变textbox2的值
     Set_Text = new set_Text(setTextbox2Text);//实例化
     for (i=5;i<10;i++)
     {
     	 this.textBox2.Invoke(Set_Text, new object[] { "world_" + i.ToString() });//通过调用委托,来该表label的值
     	 Thread.Sleep(1000);//线程休眠时间,单位是ms
     }
}

private void button2_Click(object sender, EventArgs e)
{
    Thread thread1 = new Thread(new ThreadStart(run2_withouteventparameter));
    thread1.Start();//用线程调用委托方法
}
delegate void setcheckBoxisTrue();//定义选择框委托
setcheckBoxisTrue SetcheckBoxisTrue;
private void setcheckbox1ed()
{
    this.checkBox1.Checked = true;
}

private void setnotcheckbox1ed()
{
    this.checkBox1.Checked = false;
}

private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
    if(checkBox1.Checked)
    {
        this.textBox1.Text = "textbox1";
    }
    else
    {
    	this.textBox1.Text = "";
    }
}
int num1 = 1, num2 = 2;

private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
{
    if (e.Node.Text == "改变button1")
    {
        this.textBox1.Text = num1.ToString();
        num1++;
    }
    else if (e.Node.Text == "改变button2")
    {
        this.textBox2.Text = num2.ToString();
        num2++;
    }
    else if (e.Node.Text == "再次改变button1")
    {
        this.textBox1.Text = (num1*10).ToString();
        this.textBox2.Text = ((num1+1) * 10).ToString();
        num1++;
    }
}
delegate void buttonclick(object sender, EventArgs e);//定义按钮委托
buttonclick ButtonClick;

private void run2_witheventparameter(EventArgs e)//带事件参数
{
    ButtonClick = new buttonclick(button1_Click);
    this.button1.Invoke(ButtonClick, new object[] { this.button1, e });
    Thread.Sleep(10000);

    ButtonClick = new buttonclick(button2_Click);
    this.button2.Invoke(ButtonClick, new object[] { this.button2, e });

    Thread.Sleep(10000);
    SetcheckBoxisTrue = new setcheckBoxisTrue(setcheckbox1ed);
    this.checkBox1.Invoke(SetcheckBoxisTrue, new object[] { });;

    Thread.Sleep(3000);
    SetcheckBoxisTrue = new setcheckBoxisTrue(setnotcheckbox1ed);
    this.checkBox1.Invoke(SetcheckBoxisTrue, new object[] { });

    Set_Text = new set_Text(setTextbox1Text);//实例化
    this.textBox1.Invoke(Set_Text, new object[] { "button3 finished" });
    Set_Text = new set_Text(setTextbox2Text);//实例化
    this.textBox2.Invoke(Set_Text, new object[] { "button3 finished" });
}

private void button3_Click(object sender, EventArgs e)
{
	Thread th = new Thread(new ThreadStart(delegate { run2_witheventparameter(e); }));
	th.Start();
}

1.3 按照Windows消息队列和线程Thread处理

在这里插入图片描述
        在C#应用程序中,执行Application.DoEvents();代码可以让程序优先处理当前处于Windows消息队列中的所有消息,直到这些消息处理结束才会执行后面的代码。在不加的时候,因为优先级的问题,程序会执行主进程的代码,再执行别代码,而加了以后就可以同步执行。调用此方法会导致在处理所有等待窗口消息时挂起当前线程。如果消息导致触发事件,则可以执行应用程序代码的其他区域。如果执行需要很长时间的操作或计算,通常最好在新线程上执行这些操作,最好在一个单独的线程中完成它。在单独的线程中运行长任务允许在不干扰UI继续平稳运行的情况下处理它们。在较大数据的循环中效率可能会很低,所以也可以通过别的方法(如多线程异步调用等)来处理。

private void run3(EventArgs e)//最好不要添加线程启动的函数
{
    for (int i = 15; i <= 20; i++)
    {
        this.textBox1.Text = i.ToString();
        Application.DoEvents();
        Thread.Sleep(1000);
    }

    TreeNode tn = new TreeNode("改变button1");
    TreeViewEventArgs tve = new TreeViewEventArgs(tn);
    this.treeView1_AfterSelect(this.treeView1, tve);
    Application.DoEvents();
    Thread.Sleep(1000);

    tn = new TreeNode("改变button2");
    tve = new TreeViewEventArgs(tn);
    this.treeView1_AfterSelect(this.treeView1, tve);
    Application.DoEvents();
    Thread.Sleep(1000);

    tn = new TreeNode("再次改变button1");
    tve = new TreeViewEventArgs(tn);
    this.treeView1_AfterSelect(this.treeView1, tve);
    Application.DoEvents();
    Thread.Sleep(1000);

    this.checkBox1.Checked = true;
    this.checkBox1_CheckedChanged(this.checkBox1, e);
    Application.DoEvents();
    Thread.Sleep(1000);

    this.checkBox1.Checked = false;
    this.checkBox1_CheckedChanged(this.checkBox1, e);
    Application.DoEvents();
    Thread.Sleep(1000);
}

private void button4_Click(object sender, EventArgs e)//点击button4后5s内每隔1s改变textbox4的值
{
    run3(e);
}

2 项目实践

2.1 新建C#Windows窗体应用程序

        打开VS 2015,文件->新建->项目,选择C#下的Windows中的Windows窗体应用程序,项目名称输入AutoExecuteCSharpWindowsFormApplication后点击确定后,会自动新建一个Form1窗体,在Program.cs代码中可以看到主函数作为应用程序的入口,启动了Form1。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
        此时如果直接运行结果如下图所示:
在这里插入图片描述

2.2 向Form1窗体拖动相关控件并完善功能

        下面打开视图中的工具箱,在From1.cs[设计]界面,将左侧工具箱中所需的控件直接拖动到Form1上,这里拖动的控件包括:2个TextBox、1个Timer、1个CheckBox、1个TreeView和4个Button,如下图所示。
在这里插入图片描述
        对于textbox1和textbox2控件,只需要定义以下委托函数改变其值即可。

delegate void set_Text(string s);//定义文本框委托
set_Text Set_Text;//定义一个委托实例对象

private void setTextbox1Text(string s)//通过字符串来改变textbox1值的自定义方法
{
    this.textBox1.Text = s;
}

private void setTextbox2Text(string s)//通过字符串来改变textbox2值的自定义方法
{
    this.textBox2.Text = s;
}

private void run2_withouteventparameter()//不带事件参数
{
    //前5秒动态改变textbox1的值
    Set_Text = new set_Text(setTextbox1Text);//实例化
    for (i = 0; i < 5; i++)
    {
        this.textBox1.Invoke(Set_Text, new object[] { "Hello_" + i.ToString() });//通过调用委托来改变textbox1的值
        Thread.Sleep(1000);//线程休眠1s,隔一秒再执行
    }
    //后5秒动态改变textbox2的值
    Set_Text = new set_Text(setTextbox2Text);//实例化
    for (i = 5; i < 10; i++)
    {
        this.textBox2.Invoke(Set_Text, new object[] { "world_" + i.ToString() });//通过调用委托,来该表label的值
        Thread.Sleep(1000);//线程休眠时间,单位是ms
    }
}

在这里插入图片描述
        选中timer1控件在右侧的属性窗口的事件图标下找Tick后双击进入timer1_Tick函数,在函数中编写定时器要执行的功能代码

int i;
private void run1()
{
    i = 0;
    this.timer1.Interval = 1000;//设置time1的间隔时间
    this.timer1.Start();//定时器开始计时
}

private void timer1_Tick(object sender, EventArgs e)
{
    i++;
    if (i >= 5)//if条件里加入判断代码,这里设置5s后停止 
    {
        this.timer1.Stop();//定时器停止计时
    }
    this.textBox1.Text = "Hello!" + i.ToString();//计时器在停止之前计时过程中要执行的操作,这里让文本框随时间动态显示文本
    this.textBox2.Text = "World!" + i.ToString();
}

在这里插入图片描述
        选中checkBox1控件在右侧的属性窗口的事件图标下找CheckedChanged后双击进入checkBox1_CheckedChanged函数,在函数中编写定时器要执行的功能代码

delegate void setcheckBoxisTrue();//定义选择框委托
setcheckBoxisTrue SetcheckBoxisTrue;

private void setcheckbox1ed()
{
    this.checkBox1.Checked = true;
}

private void setnotcheckbox1ed()
{
    this.checkBox1.Checked = false;
}

private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
    if (checkBox1.Checked)
    {
        this.textBox1.Text = "textbox1";
    }
    else
    C# Windows 窗体 ListView 在按宽度自动调整大小 = -1 后获取列的实际宽度?

C#如何在 Windows 窗体应用程序中使用事件

如何在 Windows 窗体中分离 UI 线程和进程线程

如何将我的 VBA 宏转换为 C# 以在 Windows 窗体应用程序中使用?

关于C# 窗体自动隐藏和加载的问题

C# Windows 窗体 - 带有事件的不可见元素(单击和 MouseEnter/Leave)