辜渝傧

13037102709

027-87870986

教学实训

您当前的位置:首页 > 教学资源 > 实训方案 >

C#应用实训|任务2 委托实现页面刷新

发布者:唯众    布时间:2020-12-21 11:49:07    点击量:

任务描述

        在任务1中通过设置Control.CheckForIllegalCrossThreadCalls = false;避免了系统对子线程访问主线程更新UI控件的安全检查,这样可以避免程序因为刷新界面出现的“假死”现象,但在实际应用中,因为多线程可能同时访问主线程同一控件,在线程数不多的情况下可能看不出问题,但在线程数量增多及访问UI控件频率增大的情况下可能导致数据错误,因此当子线程访问主线程申请控制UI控件后,最好有一个应答的过程,在访问前申请,在访问后告之,任务2通过委托及control.Invoke 和 Control.BeginInvoke实现UI控件的刷新实现项目功能。

知识引入

  1. 委托
        委托是.NET Framework引入的概念,它是面向对象的,类似于C语言中的函数指针,通过委托可以调用C#中的方法,委托是一种特殊的对象类型,定义一个委托可以同时引用多个方法,委托只是定义了这一类方法的参数类型和参数个数,不指定具体的方式功能,在实例化委托时通过方法参数具体到特定的方法,通过调用委托实现方法的调用执行。
使用委托方法如下:
  • 定义委托
  • 实例化委托
  • 调用委托
        在     C#中使得delegate关键字定义委托,语法为:
[访问修饰符] deletate   返回值类型  委托名([参数列表]);如
public   deletate  int   GetData( int  a, int  b);
5-4
using System;
using System.Collections.Generic;
using System.Text;
namespace Demo5_4
{
    class Program
    {
        //定义委托
        public delegate int GetData(int n);
        public static int GetSum(int n)
        {
            int sum = 0;
            for (int i = 1; i <= n;i++ )
            {
                sum += i;
            }
            return sum;
        }
        public static int GetFac(int n)
        {
            int fac = 1;
            for (int i = 1; i <= n; i++)
            {
                fac *= i;
            }
            return fac;
        }
        static void Main(string[] args)
        {
            GetData getsum = new GetData(GetSum);
            GetData getfac = new GetData(GetFac);
            Console.WriteLine(getsum(5));
            Console.WriteLine(getfac(5));
        }
    }
}
程序运行输出结果如图5-7所示:
图5-7  程序运行结果图
这时委托指向的是静态方法,如果委托指向实例方法,需要通过类的实例对象调用方法。
5-5
public delegate  void  show();
    class Demo5
    {
        public void msgShow()
        {
            Console.WriteLine("考试时间到");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            show msgshow = new show( new Demo5().msgShow);
            msgshow();
        }
    }
在程序开发中,如果有的方法调用必须使用委托作参数,也可不定义委托指向的方法,使用匿名委托或实例化委托时使用匿名方法。
5-6
public delegate void show();
    class Program
    {
        static void Main(string[] args)
        {
            show msgshow = delegate(){
                Console.WriteLine("下课了");
            };
            msgshow();
        }
    }
  1. Invoke( )和BeginInvoke( )
Control.Invoke (Delegate) :在拥有此控件的基础窗口句柄的线程上执行指定的委托。
Control.BeginInvoke (Delegate) :在创建控件的基础句柄所在线程上异步执行指定委托。的windows窗体应用程序中,子线程更新主线程创建UI控件,经常通过后台线程实现调用Invoke( )和Begininvoke( )方法与主线程发送消息。
5-7
下面使用委托及Invoke( )方法实现主线程UI控件刷新,程序运行如图5-8所示:
图5-8  程序运行效果图
点击按钮“button1”后,上面的标签在“红色”变为“蓝色”,并且每隔2 秒在两种颜色之间进行切换。
public delegate void UpdateUI();
        public Form2()
        {
            InitializeComponent();
        }
        private void setText()
        {
            while (true)
            {
                if(InvokeRequired)
                {
                if (label1.Text.Equals("红色"))
                {
                    this.Invoke(new UpdateUI(delegate()
                    {
                        label1.Text = "蓝色";
                    }));  
                }
                else
                {
                    this.Invoke(new UpdateUI(delegate()
                    {
                        label1.Text = "红色";
                    }));  
                }
                Thread.Sleep(2000);
                }
            }
        }
        private void button1_Click(object sender, EventArgs e)
        {
            UpdateUI updateUi = new UpdateUI(setText);
            Thread t = new Thread(new ThreadStart(updateUi));
            t.IsBackground = true;
            t.Start();
        }

任务实现

新建Windows窗体应用程序项目,修改任务1后台代码如下:
  public partial class Form1 : Form
    {
        public delegate void UpdateUI();
        public Form1()
        {
            InitializeComponent();
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            Thread t = new Thread(new ThreadStart(setVal));
            t.IsBackground = true;
            t.Start();  
        }
        //随机生成温度
        private int getWd()
        {
            int result = -1;
            Random rand = new Random();
            result = rand.Next(20,35);
            return result;
        }
        //随机生成光敏
        private int getPhoto()
        {
            int result = -1;
            Random rand = new Random();
            result = rand.Next(50, 150);
            return result;
        }
        //读取值
       private  void setVal()
        {
            while (true)
            {
                if (InvokeRequired)
                {
                    int wdNum = getWd();
                    int photoNum = getPhoto();
                    this.Invoke(new UpdateUI(delegate()
                    {
                        lblTemp.Text = wdNum.ToString();
                        if (wdNum >= 28)
                        {
                            lblFs.Text = "打开";
                        }
                        else
                        {
                            lblFs.Text = "关闭";
                        }
                        lblPhoto.Text = photoNum.ToString();
                        if (photoNum >= 100)
                        {
                            lblRgb.Text = "打开";
                        }
                        else
                        {
                            lblRgb.Text = "关闭";
                        }
                    }));
                    Thread.Sleep(3000);
                }
            }
        }
    }

任务小结

  1. 委托使关键字delegate进行定义。
  2. 委托类似于C语言的函数指针,委托在实例化时的参数为方法名。
  3. 子线程通过Invoke( )和Begininvoke( )方法与主线程发送消息。


上一篇:C#应用实训|任务1 线程实现页面刷新

下一篇:C#应用实训|任务3 事件引发页面刷新