c# 多线程 ui winform界面

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c# 多线程 ui winform界面相关的知识,希望对你有一定的参考价值。

我现在有个问题:
我在 一个button的click事件中调用了一个线程
private void button1_Click(object sender, EventArgs e)

thread t=new thread(SetValue);
t.start();
text1.text="finish";
……………………//还有一些代码

现在我想让这个线程中的方法完成之后再执行text1.text="finish";以及以后的语句。我该怎么办呢?能否详细说明一下

private void button1_Click(object sender, EventArgs e)

Thread t=new Thread(new ThreadStart(SetValue));
t.Start();
t.Join();
text1.text="finish";
……………………//还有一些代码

这段代码的效果是在执行完线程中的方法之前,主线程一直被阻塞,也就是说你感觉程序卡住了一样,不能干其他的事情(包括移动窗体)直到线程中的方法执行完毕为止,当方法执行完毕后执行你的代码(……………………//还有一些代码)。

如果你这么写:
private void button1_Click(object sender, EventArgs e)

button1.Enabled = false;
Thread t=new Thread(new ThreadStart(SetValue));
t.Start();
t.Join();
text1.text="finish";
……………………//还有一些代码
button1.Enabled = true;



private void SetValue()

//...........线程的主要计算。
Application.DoEvents();

则效果是当你点击这个按钮时,按钮变灰,你还可以干其他的事情,当方法执行完毕后执行你的代码(……………………//还有一些代码),最后按钮恢复原状(让按钮变灰是为了不让用户重复地点击,以招致方法未完成之前又重复调用按钮触发事件。)

参考资料:脑袋

参考技术A 最简单的方法,设置Control.CheckForIllegalCrossThreadCalls的值为false(这也被认为是不安全的),将
text1.text="finish";
……………………//还有一些代码
放在线程执行的方法后面。如下:

private void button1_Click(object sender, EventArgs e)

Control.CheckForIllegalCrossThreadCalls = false;
thread t=new thread(SetValue);
t.start();

private void SetValue()

do your work here //线程的主要计算。
text1.text="finish";
……………………//还有一些代码


如何实现线程安全,请参考:
http://msdn.microsoft.com/en-us/library/ms171728(VS.90).aspx
参考技术B ui控键除了主线程,其他是不可以访问的,但是想要访问还是可以的。
private void button1_Click(object sender, EventArgs e)

Control.CheckForIllegalCrossThreadCalls = false;
thread t=new thread(SetValue);
t.start();

private void SetValue()

//线程最后代码
text1.Invoke(new Action(SetTextValue));


private void SetTextValue()
text1.text = "finish";
参考技术C 如果是要用多线程里面来设置的话,是不行的
因为.NET的UI只能是在创建线程内修改,这是.NET机制决定的
如果一定要在多线程内修改的话,需要用text1.Invoke方法
详细请参见MSDN
参考技术D 那把text1.text="finish";放在要签名中的方法中不就行了吗?放在方法中最后一句。线程本身有停止的方法,但线程一般是循环执行的。

多线程更新UI的常用方法

     开发Winform或者WPF相关GUI程序中,遇到执行耗时程序片段,并且需要在ui界面上实时展示状态信息的问题时,为了防止界面出现假死状态,会用到多线程技术,异步跨线程访问ui界面元素;下面总结下Winform和WPF中常用的几种异步跨线程访问ui界面的技术。

Winform中常用技术

 1、采用BackgroundWorker控件

public partial class Form1 : Form
    {
        private BackgroundWorker worker;
        public Form1()
        {
            InitializeComponent();
            worker = new BackgroundWorker();
            worker.WorkerReportsProgress = true;// To report progress from the background worker we need to set this property
            worker.DoWork += worker_DoWork;// This event will be raised on the worker thread when the worker starts
            worker.ProgressChanged += worker_ProgressChanged;// This event will be raised when we call ReportProgress
        }

        private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progressBar1.Value = e.ProgressPercentage;
            lblPercent.Text = string.Format("{0}%", e.ProgressPercentage);
            if (e.ProgressPercentage == 100)
            {
                MessageBox.Show("数据处理完毕!");
            }
        }

        private void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            for (int i = 1; i <= 100; i++)
            {
                // Report progress to ‘UI‘ thread
                worker.ReportProgress(i);
                Thread.Sleep(100);
            }
        }

        private void btnCompute_Click(object sender, EventArgs e)
        {
            //Start the background worker
            worker.RunWorkerAsync();
        }
    }

2、采用Timer控件

public partial class Form1 : Form
    {
        private Timer timer;
        private int current;
        public Form1()
        {
            InitializeComponent();
            timer = new Timer();
            timer.Interval = 500;
            timer.Tick += timer_Tick;
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            progressBar1.Value = current;
            lblPercent.Text = string.Format("{0}%", current);
            if (current == 100)
            {
                timer.Stop();
                MessageBox.Show("数据处理完毕!");
            }
        }

        private void btnCompute_Click(object sender, EventArgs e)
        {
            Thread thread = new Thread(new ThreadStart(doWork));
            thread.Start();
            timer.Start();
        }

        private void doWork()
        {
            for (int i = 1; i <= 100; i++)
            {
                current = i;
                Thread.Sleep(100);
            }
        }
    }

3、采用委托的方式

public partial class Form1 : Form
    {
        private delegate void UpdateProgress(int percent);
        public Form1()
        {
            InitializeComponent();
        }

        private void btnCompute_Click(object sender, EventArgs e)
        {
            Thread thread = new Thread(new ThreadStart(doWork));
            thread.Start();
        }

        private void doWork()
        {
            for (int i = 1; i <= 100; i++)
            {
                //progressBar1.BeginInvoke((Action)(() => { progressBar1.Value = i; }));
                //lblPercent.BeginInvoke((Action)(() => { lblPercent.Text = string.Format("{0}%", i); }));
                //if (i == 100)
                //{
                //    MessageBox.Show("数据处理完毕!");
                //}
                update(i);
                Thread.Sleep(100);
            }
        }

        private void update(int percent)
        {
            if (InvokeRequired)
            {
                this.Invoke(new UpdateProgress(update), percent);
            }
            else
            {
                progressBar1.Value = percent;
                lblPercent.Text = string.Format("{0}%", percent);
                if (percent == 100)
                {
                    MessageBox.Show("数据处理完毕!");
                }
            }
        }
    }

WPF中常用技术

     WPF中引入了Dispatcher,常用来解决非ui线程中更新ui控件状态的问题。

/// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        private delegate void UpdateProgress(int percent);
        public MainWindow()
        {
            InitializeComponent();
        }

        private void BtnCompute_OnClick(object sender, RoutedEventArgs e)
        {
            Task task = new Task(DoWork);
            task.Start();
        }

        private void DoWork()
        {
            for (int i = 1; i <= 100; i++)
            {
                //Dispatcher.BeginInvoke((Action)(() =>
                //{
                //    progressBar1.Value = i;
                //    lblPercent.Content = string.Format("{0}%", i);
                //    if (i == 100)
                //    {
                //        MessageBox.Show("数据处理完毕!");
                //    }
                //}));
                Dispatcher.BeginInvoke(new UpdateProgress(Update), i);
                Thread.Sleep(100);
            }
        }

        private void Update(int percent)
        {
            progressBar1.Value = percent;
            lblPercent.Content = string.Format("{0}%", percent);
            if (percent == 100)
            {
                MessageBox.Show("数据处理完毕!");
            }
        }
    }

以上是关于c# 多线程 ui winform界面的主要内容,如果未能解决你的问题,请参考以下文章

C# winform 多线程更新数据,UI卡顿现象。

C# winform程序,UI界面锁死。如何处理?

C# winform多线程案例

多线程更新UI的常用方法

我用C# winform多线程,窗口就假死,等到线程全部完成了才可以点击。请问要怎么才可以让窗口不假死。

C#多线程实现循环。界面会假死怎么办?