首页 > 其他分享 >WPF知识点全攻略15- 线程处理

WPF知识点全攻略15- 线程处理

时间:2023-05-09 13:44:42浏览次数:53  
标签:知识点 15 int backgroundWorker 全攻略 private 线程 BackgroundWorker public

使用WPF构建应用程序时,想要保证系统的流畅性、用户的体验性,处理好UI线程(主线程)与其他线程(子线程)的关系是必要的。

以最近大火的直播带货为例,镜头前主播(部分副播)的语言动作是主线程,镜头外的场控、客服等人员,各自都有一个属于自己的子线程。场控在做软硬件调试、商品上架下架、发优惠信息,临时更改产品价格、数据监测,客服处理已经出单,物流,复购,销售统计等等操作,这些不可能都交给主播来做,不然时不时的冷场就太尴尬了。要让场控、客服等在镜头外做好辅助工作,并适时的把需要展示的信息传递给主播,才能保证直播的质量。

回归代码本身,要处理线程问题,一般使用Dispatcher和BackgroundWorker来处理子线程与主线程的交互。

1、Dispatcher使用

 新建一个简单的WPF项目、只放置一个Button和一个TextBlock,点击Button,使用子线程修改TextBlock的值

    <StackPanel VerticalAlignment="Center" Orientation="Horizontal">
        <Button
            Margin="10,0"
            Click="Button_Click"
            Content="变更" />
        <TextBlock
            Name="txt"
            VerticalAlignment="Center"
            Text="1" />
    </StackPanel>
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Thread thread = new Thread(UpdateText);
            thread.Start();
        }

        private void UpdateText()
        {
            Thread.Sleep(TimeSpan.FromSeconds(1));

            //1、直接修改,报错:System.InvalidOperationException:“调用线程无法访问此对象,因为另一个线程拥有该对象。”
            //this.txt.Text = "New text";

            //2、使用Dispatcher,把子线程的方法,丢回给主线程执行。
            Dispatcher.BeginInvoke(new Action(() =>
            {
                this.txt.Text = "New text";
            }));
        }

明显 Dispatcher的使用,把子线程中需要操作主线程的部分,丢回给了主线程,这样完美结果了更改报错的问题。但这种写法不适合在其方法内部处理耗时任务,同时过多的使用Thread来处理异步方法,也会带来不易管理、处理共享数据加锁等问题。

处理简单逻辑是可以使用Dispatcher,处理较为耗时、可能牵扯共享数据或者为方便的管理子线程的启动、停止等,微软提供了BackgroundWorker组件,来安全的处理这些问题。

2、BackgroundWorker的使用

 下面代码实现了一个查找指定范围整数范围内的所有素数的功能,XAML代码如下:

        <Grid Margin="5">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>

            <TextBlock Margin="5">起始:</TextBlock>
            <TextBox
                Name="txtFrom"
                Grid.Column="1"
                Margin="5">
                1
            </TextBox>
            <TextBlock Grid.Row="1" Margin="5">结束:</TextBlock>
            <TextBox
                Name="txtTo"
                Grid.Row="1"
                Grid.Column="1"
                Margin="5">
                500000
            </TextBox>

            <StackPanel
                Grid.Row="2"
                Grid.Column="1"
                Orientation="Horizontal">
                <Button
                    Name="cmdFind"
                    Margin="5"
                    Padding="3"
                    Click="cmdFind_Click">
                    查找素数
                </Button>
                <Button
                    Name="cmdCancel"
                    Margin="5"
                    Padding="3"
                    Click="cmdCancel_Click"
                    IsEnabled="False">
                    停止
                </Button>
            </StackPanel>

            <TextBlock Grid.Row="3" Margin="5">结果:</TextBlock>
            <ListBox
                Name="lstPrimes"
                Grid.Row="3"
                Grid.Column="1"
                Margin="5" />

            <TextBlock Grid.Row="4" Margin="5">进度:</TextBlock>
            <ProgressBar
                Name="progressBar"
                Grid.Row="4"
                Grid.Column="1"
                Height="20"
                MinHeight="20"
                Margin="5"
                VerticalAlignment="Bottom"
                Maximum="100"
                Minimum="0" />
        </Grid>

.cs中的C#代码如下:

        public MainWindow()
        {
            InitializeComponent();
           
            backgroundWorker = new BackgroundWorker();
            backgroundWorker.WorkerReportsProgress = true;
            backgroundWorker.WorkerSupportsCancellation = true;

            backgroundWorker.DoWork += backgroundWorker_DoWork;
            backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted;
            backgroundWorker.ProgressChanged += backgroundWorker_ProgressChanged;
        }


        private BackgroundWorker backgroundWorker;

        private void cmdFind_Click(object sender, RoutedEventArgs e)
        {
            // 控制按钮、清空数据
            cmdFind.IsEnabled = false;
            cmdCancel.IsEnabled = true;
            lstPrimes.Items.Clear();

            // 获取整数方位
            int from, to;
            if (!Int32.TryParse(txtFrom.Text, out from))
            {
                MessageBox.Show("Invalid From value.");
                return;
            }
            if (!Int32.TryParse(txtTo.Text, out to))
            {
                MessageBox.Show("Invalid To value.");
                return;
            }

            // 使用RunWorkerAsync,在子线程中拾取所有素数
            FindPrimesInput input = new FindPrimesInput(from, to);
            backgroundWorker.RunWorkerAsync(input);
        }

        /// <summary>
        /// BackgroundWorker执行方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            // 获取传入参数
            FindPrimesInput input = (FindPrimesInput)e.Argument;

            // 开始素数拾取
            int[] primes = Worker.FindPrimes(input.From, input.To, backgroundWorker);

            if (backgroundWorker.CancellationPending)
            {
                e.Cancel = true;
                return;
            } 
            // 返回结果
            e.Result = primes;
        }

        /// <summary>
        /// BackgroundWorker执行完成
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled)
            {
                MessageBox.Show("Search cancelled.");
            }
            else if (e.Error != null)
            {
                // An error was thrown by the DoWork event handler.
                MessageBox.Show(e.Error.Message, "An Error Occurred");
            }
            else
            {
                int[] primes = (int[])e.Result; //结果放入ListBox
                foreach (int prime in primes)
                {
                    lstPrimes.Items.Add(prime);
                }
            }

            //重置按钮、进度
            cmdFind.IsEnabled = true;
            cmdCancel.IsEnabled = false;
            progressBar.Value = 0;
        }

        /// <summary>
        /// BackgroundWorker执行进度
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progressBar.Value = e.ProgressPercentage;//变更进度显示
        }

        /// <summary>
        /// 取消
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmdCancel_Click(object sender, RoutedEventArgs e)
        {
            backgroundWorker.CancelAsync();
        }

         

Worker.cs:

    public class FindPrimesInput
    {
        public int To
        { get; set; }

        public int From
        { get; set; }

        public FindPrimesInput(int from, int to)
        {
            To = to;
            From = from;
        }

    }

    public class Worker
    {
        public static int[] FindPrimes(int fromNumber, int toNumber)
        {
            return FindPrimes(fromNumber, toNumber, null);
        }

        public static int[] FindPrimes(int fromNumber, int toNumber, System.ComponentModel.BackgroundWorker backgroundWorker)
        {
            int[] list = new int[toNumber - fromNumber];

            // Create an array containing all integers between the two specified numbers.
            for (int i = 0; i < list.Length; i++)
            {
                list[i] = fromNumber;
                fromNumber += 1;
            }


            //find out the module for each item in list, divided by each d, where
            //d is < or == to sqrt(to)
            //if the remainder is 0, the nubmer is a composite, and thus
            //we mark its position with 0 in the marks array,
            //otherwise the number is a prime, and thus mark it with 1
            int maxDiv = (int)Math.Floor(Math.Sqrt(toNumber));

            int[] mark = new int[list.Length];


            for (int i = 0; i < list.Length; i++)
            {
                for (int j = 2; j <= maxDiv; j++)
                {

                    if ((list[i] != j) && (list[i] % j == 0))
                    {
                        mark[i] = 1;
                    }

                }

                
                int iteration = list.Length / 100;
                if ((i % iteration == 0) && (backgroundWorker != null))
                {                
                    if (backgroundWorker.CancellationPending)
                    {
                        // Return without doing any more work.
                        return null;                      
                    }

                    if (backgroundWorker.WorkerReportsProgress)
                    {
                        //float progress = ((float)(i + 1)) / list.Length * 100;
                        backgroundWorker.ReportProgress(i / iteration);
                        //(int)Math.Round(progress));
                    }
                }

            }

            //create new array that contains only the primes, and return that array
            int primes = 0;
            for (int i = 0; i < mark.Length; i++)
            {
                if (mark[i] == 0) primes += 1;

            }

            int[] ret = new int[primes];
            int curs = 0;
            for (int i = 0; i < mark.Length; i++)
            {
                if (mark[i] == 0)
                {
                    ret[curs] = list[i];
                    curs += 1;
                }
            }

            if (backgroundWorker != null && backgroundWorker.WorkerReportsProgress)
            {
                backgroundWorker.ReportProgress(100);
            }

            return ret;

        }
         
    }
View Code

执行效果:

 

BackgroundWorker的DoWork事件不可操作主线程(界面对象),用来完成一些其他耗时的后台任务,RunWorkerCompleted事件把执行结果反馈给主线程,ProgressChanged事件把执行进度反馈给主线程。

简单总结一下,Dispatcher是一种简单粗暴的处理多线程问题的方式,适合业务逻辑简单线程少的场景,BackgroundWorker则是一种安全、可控的方式,非常适用于后台文件上传下载、应用更新、实时监控等与界面交互较多场景。对于其他与界面交互不多的场景,则使用.NET的线程支持(async/await等)自主实现。

 

WPF知识点全攻略目录:https://www.cnblogs.com/kuangxiangnice/p/11040070.html

标签:知识点,15,int,backgroundWorker,全攻略,private,线程,BackgroundWorker,public
From: https://www.cnblogs.com/kuangxiangnice/p/17371670.html

相关文章

  • 最新版本Camera Raw 15.3增效工具,新增AI功能
    Ps关于CameraRaw滤镜的消息大家都听了很多很多了,今天给大家分享的就是CameraRaw的最新版本,也就是那个传说中增加了AI功能的版本。对比先前两个版本,15.3在功能上也就做了2个值得关注的更新:1.AI降噪;2.AI智能蒙板。而改动最大的就是蒙版的支持,目前来看,多个AI蒙版的选择和使......
  • 【2023.05.08】keepley周杰伦DZ0155周同学积木评测
    前言本人是自费购买积木,购买原因是给妹妹培养动手能力,减少短视频占用时间,其次是给家里做摆饰,所以选择积木多考虑了美观非专业评测,如果想看更多积木评测请点进我的博客主页分类查看正文原本这个积木是粉色的,改成黑色替换件的话比较麻烦,简便的方法是将原包装内的粉色挑出来(因......
  • PowerDesigner15在生成SQL時報錯Generation aborted due to errors detected during t
    1.用PowerDesigner15建模,在Database—>GenerateDatabase(或者用Ctrl+G快捷鍵)來生產sql語句,卻提示“Generationabort1.用PowerDesigner15建模,在Database—>GenerateDatabase(或者用Ctrl+G快捷鍵)來生產sql語句,卻提示“Generationabortedduetoerrorsdetectedduringthe......
  • 15th
    分糖果问题源代码#include<iostream>usingnamespacestd;intjudge(intc[]){ inti; for(i=0;i<10;i++) if(c[0]!=c[i]) return1; return0;}intmain(){ intcount=0; inta[10]={10,2,8,22,16,4,10,6,14,20}; intb[10]; while(judge(a)){ count++; for(inti=0;......
  • Wallys 2×2.4GHz 2x5GHz/ #MT7915 #MT7975 /support openwrt
    DR7915https://www.wallystech.com/Network_Card/DR7915-wifi6-MT7915-MT7975-2T2R-support-OpenWRT-802.11AX-supporting-MiniPCIe-Module.htmlMT7915+MT7975 Chipset2.4GHzmax23dBm&5GHzmax20dBmoutputpower IEEE802.11ac /axcompliant&backwardcompa......
  • Wallys 2×2.4GHz 2x5GHz/ #MT7915 #MT7975 /support openwrt
    DR7915https://www.wallystech.com/Network_Card/DR7915-wifi6-MT7915-MT7975-2T2R-support-OpenWRT-802.11AX-supporting-MiniPCIe-Module.htmlMT7915+MT7975 Chipset2.4GHzmax23dBm&5GHzmax20dBmoutputpower IEEE802.11ac /axcompliant&backwardcompa......
  • 为设计师准备的 15 个免费新鲜的字体
    AxeHandelGoingFastKa-Boing!NoasarckFreshMakerHalcyoniaMANABUMAJORGUILTYRemodulaGalapogosLainieDayButterFingerPonyMakerRangerGrigovia djdesignerlab......
  • 当前主机存在Sudo CVE-2021-3156漏洞:Sudo1.8.23升级1.9.5p2
    Sudo权限绕过漏洞(CVE-2019-14287)Sudo缓冲区溢出漏洞(CVE-2021-3156)根据安全漏洞CVE-2021-3156,受影响的Sudo版本:Sudo版本1.7.7到1.7.10p9、1.8.2到1.8.31p2和1.9.0到1.9.5p1受到影响。sudo官网:https://www.sudo.ws/sudo下载地址:https://www.sudo.ws/getting/do......
  • 2. 预备知识点
    1.注释#井号标注的文本2.数字整数intPython3开始不再区分long、int,long被重命名为int,所以只有int类型了进制表示:十进制10十六进制0x10八进制0o10二进制0b10bool类型,有2个值True、False浮点数float1.2、3.1415、-0.12,1.46e9等价于科学计数法1.46*109本质上使用了C......
  • hdu 1599 find the mincost route(无向图的最小环:求从一个点遍历所有节点以后回到原点
    题目:findthemincostrouteTimeLimit:1000/2000MS(Java/Others)    MemoryLimit:32768/32768K(Java/Others)TotalSubmission(s):2801    AcceptedSubmission(s):1115ProblemDescription杭州有N个景区,景区之间有一些双向的路来连接,现在8600想找一条旅游......