Winform之UI后台线程

多线程,一个古老的话题,今天我来聊下最基本的线程,UI线程和后台线程。

在后台线程中直接操作UI控件会出现异常(线程间操作无效:从不是创建控件“XX”的线程访问它)。怎么解决这个问题那?关键点在代理和InvokeRequired属性,Winform的UI(窗口)代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using LandpyLibrary;
using LandpyCommon;

namespace LandpyWindowsForm
{
    
public partial class MainForm : Form, IFormWorkThread
    {
        
public MainForm()
        {
            InitializeComponent();
            cdObj 
= SetTime;
        }

        
private delegate void ControlDelegate(string time);
        
private WorkThread wtObj;
        ControlDelegate cdObj;

        
private void SetTime(string time)
        {
            lblTime.Text 
= time;
        }

        
public void ShowTime(string time)
        {
            
if (lblTime.InvokeRequired)
            {
                Invoke(cdObj, time);
            }
            
else
            {
                SetTime(time);
            }
        }

        
private void btnStart_Click(object sender, EventArgs e)
        {
            wtObj 
= new WorkThread(this);
            wtObj.StartShowTime();
        }

        
private void btnEnd_Click(object sender, EventArgs e)
        {
            
if (wtObj != null)
            {
                wtObj.EndShowTime();
            }
        }

        
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            
if (wtObj != null)
            {
                wtObj.EndShowTime();
            }
        }
    }
}

为了能在后台线程中操作UI线程,我们的MainForm继承了公共接口IFormWorkThread,接口定义如下:

using System;
using System.Collections.Generic;
using System.Text;

namespace LandpyCommon
{
    public interface IFormWorkThread
    {
        void ShowTime(string time);
    }
}

该接口放在一个独立的Dll中,UI线程和后台线程也均处于不同的程序集中,它们均引用了该接口的Dll。

后台线程类如下:

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

using LandpyCommon;

namespace LandpyLibrary
{
    
public class WorkThread
    {
        
private IFormWorkThread _formWorkThread;
        
private Thread thread;

        
public WorkThread(IFormWorkThread formWorkThread)
        {
            _formWorkThread 
= formWorkThread;
        }

        
public void Deal()
        {
            
while (true)
            {
                Thread.Sleep(
1000);
                _formWorkThread.ShowTime(DateTime.Now.ToString());
            }
        }

        
public void StartShowTime()
        {
            thread 
= new Thread(new ThreadStart(Deal));
            thread.Name 
= "TimeThread";
            thread.Start();
        }

        
public void EndShowTime()
        {
            thread.Abort();
        }
    }
}

其实报异常是因为多线程操作UI控件是非安全的,MS提供了解决方案,关键代码如下:

        public MainForm()
        {
            InitializeComponent();
            cdObj = SetTime;
        }

        private delegate void ControlDelegate(string time);
        ControlDelegate cdObj;

        private void SetTime(string time)
        {
            lblTime.Text = time;
        }

        public void ShowTime(string time)
        {
            if (lblTime.InvokeRequired)
            {
                Invoke(cdObj, time);
            }
            else
            {
                SetTime(time);
            }
        }

通过代理和InvokeRequired属性解决了这个问题。

敬告

作者:pangxiaoliang
出处:http://www.cnblogs.com/pangxiaoliang
本文版权归pangxiaoliang和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,谢谢合作。
原文地址:https://www.cnblogs.com/pangxiaoliang/p/1512729.html