当前位置:网站首页 / WPF / 正文

[Aaronyang] 写给自己的WPF4.5 笔记16[多线程]

时间:2015年03月04日 | 作者 : aaronyang | 分类 : WPF | 浏览: 4808次 | 评论 0

  =============潇洒的版权线==========www.ayjs.net===== Aaronyang ========= AY =========== 安徽 六安 杨洋 ==========   未经允许不许转载 =========

System.Windows.Threading.Dispatcher类(wpf新增的)

DispatcherObject类(Dispatcher,CheckAccess(),VerifyAccess())

具有线程关联性的WPF对象都在类层次的某个位置继承自DispatcherObject类。


 

demo1:普通线程方式

界面:

<Grid>
        <Button x:Name="btn1" Content="更新文本" HorizontalAlignment="Left" Margin="209,50,0,0" VerticalAlignment="Top" Width="75" Click="btn1_Click"/>
        <TextBox x:Name="tb1" HorizontalAlignment="Left" Height="23" Margin="26,50,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="120"/>

    </Grid>

后台:

private void btn1_Click(object sender, RoutedEventArgs e)
        {
            Thread t = new Thread(updateTxt);
            t.Start();
        }

        private void updateTxt()
        {
            Thread.Sleep(TimeSpan.FromSeconds(5));
            tb1.Text = "你好阳光";
        }

失败了

updateTxt()方法在新线程上运行,不允许访问WPF对象。TextBox对象调用VerifyAccess()方法捕获异常。(aaronyang博客)

使用WPF方式将操作封送到调度程序线程即可

private void updateTxt()
        {
            Thread.Sleep(TimeSpan.FromSeconds(5));
            //tb1.Text = "你好阳光";
            this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)delegate()
            {
                tb1.Text = "你好阳光";
            });
        }

此时拖动窗口也没有卡顿。5秒后自动更新界面。第一个参数是优先级。DispatcherPriority.SystemIdle表示CPU空闲状态。DispatcherPriority.ApplicationIdle应用程序空闲时候再操作。

BeginInvoke返回线程信息,可控制,也可以获得执行状态,我在前台加了个进度条

private void updateTxt()
        {
            Thread.Sleep(TimeSpan.FromSeconds(5));
            //tb1.Text = "你好阳光";
            //this.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, (ThreadStart)delegate()
            //{
            //    tb1.Text = "你好阳光";
            //});

            //可用于判断是否完成
            var dispatcherOperation = this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)delegate()
            {
                Thread.Sleep(TimeSpan.FromSeconds(5));
                tb1.Text = "你好阳光";
            });
            while (!(dispatcherOperation.Status==DispatcherOperationStatus.Completed))
            {
               
             }
            this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)delegate()
            {
                pb1.Value = 100;
            });

        }

Invoke是同步的方法,BeginInvoke是异步的。


 

System.ComponentModel.BackgroundWorker类

还提供了进度事件和取消消息,由于BackgroundWorker不可见,所以声明在窗口的资源里面,我们需要引入空间

<Window x:Class="multhread.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:cm="clr-namespace:System.ComponentModel;assembly=System"
        Title="MainWindow" Height="350" Width="525">

DEMO2

   <Window.Resources>
        <cm:BackgroundWorker x:Key="bw" WorkerReportsProgress="True" WorkerSupportsCancellation="True"
            DoWork="BackgroundWorker_DoWork" RunWorkerCompleted="BackgroundWorker_RunWorkerCompleted" ProgressChanged="BackgroundWorker_ProgressChanged"
                             ></cm:BackgroundWorker>
    </Window.Resources>

后台获得

private BackgroundWorker bw;
        public int sum = 0;
        public MainWindow()
        {
            InitializeComponent();
            bw = (BackgroundWorker)this.FindResource("bw");
        }

OK,接下来我们来做个后台耗时的操作,我们使用Thread模拟吧,前台定义好界面

<Window x:Class="multhread.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:cm="clr-namespace:System.ComponentModel;assembly=System"
        Title="从1加到10 aaronyang demo" Height="350" Width="525">
    <Window.Resources>
        <cm:BackgroundWorker x:Key="bw" WorkerReportsProgress="True" WorkerSupportsCancellation="True"
            DoWork="BackgroundWorker_DoWork" RunWorkerCompleted="BackgroundWorker_RunWorkerCompleted" ProgressChanged="BackgroundWorker_ProgressChanged"
                             ></cm:BackgroundWorker>
    </Window.Resources>
    <Grid>
        <Button x:Name="btn1" Content="开始增加" HorizontalAlignment="Left" Margin="21,70,0,0" VerticalAlignment="Top" Width="75" Click="btn1_Click" IsEnabled="true"/>
        <Button x:Name="btn2" Content="取消增加" HorizontalAlignment="Left" Margin="101,70,0,0" VerticalAlignment="Top" Width="75" Click="btn2_Click" IsEnabled="False"/>

        <TextBox x:Name="tb1" HorizontalAlignment="Left" Height="23" Margin="76,10,0,0" TextWrapping="Wrap" Text="10" VerticalAlignment="Top" Width="120"/>
        <ProgressBar x:Name="pb1" HorizontalAlignment="Left" Height="16" Margin="21,108,0,0" VerticalAlignment="Top" Width="289" Maximum="100" Minimum="0"/>
        <Label Content="目标分数" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top"/>
        <Label Content="当前分数:" HorizontalAlignment="Left" Margin="10,40,0,0" VerticalAlignment="Top"/>
        <Label x:Name="lblPoint" Content="0" HorizontalAlignment="Left" Margin="78,39,0,0" VerticalAlignment="Top" RenderTransformOrigin="0,-0.2"/>

    </Grid>
</Window>

后台看代码没啥解释的。

/// <summary>
        /// 开始线程
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn1_Click(object sender, RoutedEventArgs e)
        {
            //Thread t = new Thread(updateTxt);
            //t.Start();
            btn1.IsEnabled = false;
            btn2.IsEnabled = true;
            int grade=Convert.ToInt32(tb1.Text);
            bw.RunWorkerAsync(grade);

        }

然后开始了Dowork的方法

private void BackgroundWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            int max = (int)e.Argument;
            long c = 0;
            for (int i = 1; i <= max; i++)
            {
                System.Threading.Thread.Sleep(TimeSpan.FromMilliseconds(200));//每完成1次相当于10%
                c = c + i;
                bw.ReportProgress(i * 10);
            }
            e.Result = c;
        }

dowork完以后,会返回最终结果,我们在Completed中显示结果

private void BackgroundWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                MessageBox.Show(e.Error.Message);
            }
            else {
                lblPoint.Content = e.Result.ToString();
            }
        }

我们在dowork时候,调用ReportProgress报告进度

  private void BackgroundWorker_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
        {
            pb1.Value = e.ProgressPercentage;
        }

取消线程

   //取消线程
        private void btn2_Click(object sender, RoutedEventArgs e)
        {
            bw.CancelAsync();
        }

然后,在dowork中判断,是否取消,如果取消就结束。

private void BackgroundWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            int max = (int)e.Argument;
            long c = 0;
            for (int i = 1; i <= max; i++)
            {
                if (bw.CancellationPending) {
                    e.Cancel = true;
                    return;
                }
                System.Threading.Thread.Sleep(TimeSpan.FromMilliseconds(500));//每完成1次相当于10%
                c = c + i;
                bw.ReportProgress(i * 10);
            }
            e.Result = c;
        }

        private void BackgroundWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled)
            {
                //MessageBox.Show("操作已经取消");
                pb1.Value = 0;
                btn1.IsEnabled = true;
                btn2.IsEnabled = false;
                return;
            }
            else {
                if (e.Error != null)
                {
                    MessageBox.Show(e.Error.Message);
                }
                else
                {
                    lblPoint.Content = e.Result.ToString();
                }
                btn1.IsEnabled = true;
                btn2.IsEnabled = false;
            }
        
           
           
        }

效果图:


 

这个简单的DEMO就先当这里了

  =============潇洒的版权线==========www.ayjs.net===== Aaronyang ========= AY =========== 安徽 六安 杨洋 ==========   未经允许不许转载 =========

-------------------小小的推荐,作者的肯定,读者的支持。推不推荐不重要,重要的是希望大家能把WPF推广出去,别让这么好的技术消失了,求求了,让我们为WPF技术做一份贡献。------

 

推荐您阅读更多有关于“WPF4.5,”的文章

猜你喜欢

额 本文暂时没人评论 来添加一个吧

发表评论

必填

选填

选填

必填

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

  查看权限

抖音:wpfui 工作wpf,目前主maui

招聘合肥一枚WPF工程师,跟我一个开发组,10-15K,欢迎打扰

目前在合肥市企迈科技就职

AYUI8全源码 Github地址:前往获取

杨洋(AaronYang简称AY,安徽六安人)AY唯一QQ:875556003和AY交流

高中学历,2010年开始web开发,2015年1月17日开始学习WPF

声明:AYUI7个人与商用免费,源码可购买。部分DEMO不免费

不是从我处购买的ayui7源码,我不提供任何技术服务,如果你举报从哪里买的,我可以帮你转正为我的客户,并送demo

查看捐赠

AYUI7.X MVC教程 更新如下:

第一课 第二课 程序加密教程

标签列表