WPF中的多线程(一)

首先我们先来看一个例子,用来计算一定范围内的素数个数。

XAML:

<Grid>
	<Grid.RowDefinitions>
		<RowDefinition Height="Auto"/>
		<RowDefinition Height="Auto"/>
		<RowDefinition Height="Auto"/>
		<RowDefinition Height="Auto"/>
	</Grid.RowDefinitions>
	<StackPanel Orientation="Horizontal" Margin="6">
		<TextBlock Text="From:" />
		<TextBox Margin="10,2,2,2" Width="120" MaxLength="10" x:Name="_from"/>
		<TextBlock Text="To:" Margin="20,0,0,0"/>
		<TextBox Margin="10,2,2,2" Width="120" MaxLength="10" x:Name="_to"/>
	</StackPanel>
	<StackPanel Orientation="Horizontal" Grid.Row="1" Margin="6">
		<Button Content="Calculate" Padding="4" Click="CalcButtonClick" x:Name="_calcButton"/>
		<Button Content="Cancel" Padding="4" Margin="10,0,0,0" IsEnabled="False" x:Name="_cancelButton" Click="CancleButtonClick"/>
	</StackPanel>
	<TextBlock x:Name="_result" Grid.Row="3" FontSize="20" Margin="6" HorizontalAlignment="Center" />
</Grid>

C#:

        private void CalcButtonClick(object sender, RoutedEventArgs e)
        {
            _result.Text = string.Empty;

            int from = int.Parse(_from.Text);
            int to = int.Parse(_to.Text);

            _calcButton.IsEnabled = false;

            _cancelButton.IsEnabled = true;

            int total = CountPrimes(from, to);

            _result.Text = "Total Primes: " + total.ToString();

            _calcButton.IsEnabled = true;
        }

        private int CountPrimes(int from, int to)
        {
            int total = 0;

            for (int i = from; i <= to; i++)
            {
                bool isPrime = true;
                int limit = (int)Math.Sqrt(i);
                for (int j = 2; j <= limit; j++)
                    if (i % j == 0)
                    {
                        isPrime = false;
                        break;
                    }
                if (isPrime)
                    total++;
            }
            return total;
        }

运行之后,如果输入的值很大,例如需要查找1到100000000之间的素数。发现一会儿界面就会卡死。这是因为我们的计算方法阻塞了UI线程。此时我们应该考虑将计算方法放在一个线程中去计算。将计算的代码放置在ThreadPool中,不建议使用Thread,因为ThreadPool会帮助我们来管理线程。

修改CalcButtonClick的C#代码如下:

        private void CalcButtonClick(object sender, RoutedEventArgs e)
        {
            _result.Text = string.Empty;

            int from = int.Parse(_from.Text);
            int to = int.Parse(_to.Text);

            _calcButton.IsEnabled = false;

            _cancelButton.IsEnabled = true;

            ThreadPool.QueueUserWorkItem((state) => {

                int total = CountPrimes(from, to);

                _result.Text = "Total Primes: " + total.ToString();

                _calcButton.IsEnabled = true;

            });
        }

此时查找1到100000000之间的素数,发现界面可以自由的拖拽。不过会产生一个异常。截图如下:

错误信息告诉我们在一个线程中访问另一个线程创建的对象。这是因为_result这个TextBlock是UI线程创建的。我们不能在一个后台线程中访问它。下面就要引出WPF中专门用于UI同步的Dispatcher对象。继续改进代码,

        private void CalcButtonClick(object sender, RoutedEventArgs e)
        {
            _result.Text = string.Empty;

            int from = int.Parse(_from.Text);
            int to = int.Parse(_to.Text);

            _calcButton.IsEnabled = false;

            _cancelButton.IsEnabled = true;

            ThreadPool.QueueUserWorkItem((state) => {

                int total = CountPrimes(from, to);

                Dispatcher.BeginInvoke(new Action(() =>
                {
                    _result.Text = "Total Primes: " + total.ToString();

                    _calcButton.IsEnabled = true;
                }));
            });
        }

把更新UI的代码都放置在Dispatcher.BeginInvoke中执行。这次我们会看到最终的执行结果。

细心的你会返现Dispatcher对象还有一个Invoke的方法。这两者的区别BeginInvoke是异步更新UI,不会阻塞UI,Invoke方法是同步更新UI,如果需要更新到UI的内容很多,会造成UI的阻塞,建议使用BeginInvoke。

这一篇博客先写这么多,内容太多怕影响阅读效果。后面的博客中会介绍WPF中另外同步UI的方法及取消线程中的操作。

如果您觉得博客中有错误,欢迎在评论中指出。感谢您的阅读。

时间: 2024-10-09 18:14:10

WPF中的多线程(一)的相关文章

拒绝卡顿——在WPF中使用多线程更新UI

有经验的程序员们都知道:不能在UI线程上进行耗时操作,那样会造成界面卡顿,如下就是一个简单的示例: ????public partial class MainWindow : Window????{????????public MainWindow()????????{????????????InitializeComponent();????????????this.Dispatcher.Invoke(new Action(()=> { }));????????????this.Loaded

WPF中多线程统计拆箱装箱和泛型的执行效率

WPF中多线程统计拆箱装箱和泛型的执行效率,使用的知识点有泛型.多线程.委托,从例子中可以看到使用泛型的效率至少提升2倍 MainWindow.xaml <Window x:Class="Box.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xa

WPF中多线程统计拆箱装箱和泛型的运行效率

WPF中多线程统计拆箱装箱和泛型的执行效率.使用的知识点有泛型.多线程.托付.从样例中能够看到使用泛型的效率至少提升2倍 MainWindow.xaml <Window x:Class="Box.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xa

C#中的多线程 - 同步基础

原文:http://www.albahari.com/threading/part2.aspx 1同步概要 在第 1 部分:基础知识中,我们描述了如何在线程上启动任务.配置线程以及双向传递数据.同时也说明了局部变量对于线程来说是私有的,以及引用是如何在线程之间共享,允许其通过公共字段进行通信. 下一步是同步(synchronization):为期望的结果协调线程的行为.当多个线程访问同一个数据时,同步尤其重要,但是这是一件非常容易搞砸的事情. 同步构造可以分为以下四类: 简单的阻塞方法 这些方法

C#中的多线程 - 同步基础 z

原文:http://www.albahari.com/threading/part2.aspx 专题:C#中的多线程 1同步概要Permalink 在第 1 部分:基础知识中,我们描述了如何在线程上启动任务.配置线程以及双向传递数据.同时也说明了局部变量对于线程来说是私有的,以及引用是如何在线程之间共享,允许其通过公共字段进行通信. 下一步是同步(synchronization):为期望的结果协调线程的行为.当多个线程访问同一个数据时,同步尤其重要,但是这是一件非常容易搞砸的事情. 同步构造可以

C#中的多线程 - 多线程的使用 z

原文:http://www.albahari.com/threading/part3.aspx 专题:C#中的多线程 1基于事件的异步模式Permalink 基于事件的异步模式(event-based asynchronous pattern,EAP)提供了一种简单的方式,让类可以提供多线程的能力,而不需要使用者显式启动和管理线程.它也提供如下的功能: 协作取消模型(cooperative cancellation model) 工作线程完成时安全更新 WPF 或 Windows Forms 控

C#中的多线程 - 基础知识 z

原文:http://www.albahari.com/threading/ 专题:C#中的多线程 1简介及概念Permalink C# 支持通过多线程并行执行代码,线程有其独立的执行路径,能够与其它线程同时执行. 一个 C# 客户端程序(Console 命令行.WPF 以及 Windows Forms)开始于一个单线程,这个线程(也称为“主线程”)是由 CLR 和操作系统自动创建的,并且也可以再创建其它线程.以下是一个简单的使用多线程的例子: 所有示例都假定已经引用了以下命名空间: using

C#中的多线程 - 并行编程 z

原文:http://www.albahari.com/threading/part5.aspx 专题:C#中的多线程 1并行编程Permalink 在这一部分,我们讨论 Framework 4.0 加入的多线程 API,它们可以充分利用多核处理器. 并行 LINQ(Parallel LINQ)或称为 PLINQ Parallel类 任务并行(task parallelism)构造 SpinLock 和 SpinWait 这些 API 可以统称为 PFX(Parallel Framework,并行

在 WPF 中的线程

线程处理使程序能够执行并发处理,以便它可以做多个操作一次.节省开发人员从线程处理困难的方式,设计了 WPF (窗口演示文稿基金会).这篇文章可以帮助理解线程在 WPF 中的正确用法. WPF 内部线程和规则 所有 WPF 应用程序中都运行两个线程: 为呈现-它在后台运行,所以,它被隐藏. 用于管理 UI 界面 (UI 线程) — — 大多数 WPF 对象与 UI 线程被束缚.它接收输入. 绘制屏幕. 运行的代码和处理事件. WPF 支持单线程单元模型,有以下规则: 一个线程在整个应用程序中运行,