多线程更新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("数据处理完毕!");
            }
        }
    }

转载于:https://www.cnblogs.com/harderqian/p/5588667.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
WPF中的WriteableBitmap是一个可写的位图对象,它允许我们直接在代码中更新图像的像素数据。在应对多线程更新WriteableBitmap时,我们需要考虑以下几点: 1. 使用后台线程更新:为了避免UI线程的阻塞,我们可以将更新WriteableBitmap的逻辑放在后台线程中执行。这可以通过使用BackgroundWorker或Task等多线程编程模型来实现。 2. 分割图像更新:对于大型图像,我们可以将其分割成小块,并由不同的线程分别更新这些小块。这样可以使图像更新过程更加高效,并减少多线程竞争的可能性。 3. 线程同步:由于多个线程可能同时访问WriteableBitmap的像素数据,我们需要使用线程同步机制来确保同时访问的线程之间不会产生冲突。常用的线程同步机制包括使用lock关键字、Monitor类、Mutex类等。 4. 跨线程更新UI:由于WriteableBitmap通常用于在UI上显示图像,当后台线程更新WriteableBitmap后,我们需要使用Dispatcher对象将更新操作切换回UI线程。这可以通过Dispatcher.Invoke或Dispatcher.BeginInvoke来实现。 5. 性能优化:在进行多线程更新WriteableBitmap时,我们需要考虑性能问题。例如,可以使用双缓冲技术,在后台线程中更新位图的一块区域后,再将更新的结果复制到UI线程中显示,以减少图像刷新的频率。 总之,多线程更新WriteableBitmap需要注意线程同步和性能优化的问题。我们可以使用后台线程进行更新,并使用线程同步机制确保数据访问的安全,同时在更新完成后,再将结果切换回UI线程进行显示。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值