C# WPF中的GUI多线程技巧详解

1. 使用BackgroundWorker组件

代码示例:

复制代码
go 复制代码
public partial class MainWindow : Window
{
    private BackgroundWorker backgroundWorker = new BackgroundWorker();

    public MainWindow()
    {
        InitializeComponent();
        backgroundWorker.DoWork += BackgroundWorker_DoWork;
        backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;
        backgroundWorker.WorkerReportsProgress = true;
        backgroundWorker.WorkerSupportsCancellation = true;
    }

    private void StartButton_Click(object sender, RoutedEventArgs e)
    {
        backgroundWorker.RunWorkerAsync();
    }

    private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        // 长时间运行的任务
        for (int i = 0; i < 100; i++)
        {
            if (backgroundWorker.CancellationPending)
            {
                e.Cancel = true;
                return;
            }
            backgroundWorker.ReportProgress(i + 1);
            Thread.Sleep(100);
        }
    }

    private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Cancelled)
        {
            MessageBox.Show("Task was canceled.");
        }
        else if (e.Error != null)
        {
            MessageBox.Show("Error: " + e.Error.Message);
        }
        else
        {
            MessageBox.Show("Task completed.");
        }
    }
}

优点:

  • 提供了简单的方式来异步执行操作。

  • 支持进度更新和取消操作。

缺点:

  • 编程模型较为古老,不是基于任务并行库(TPL)。

使用场景:

  • 当需要简单的异步操作且不需要复杂的任务调度时。

2. 使用Task并行库(TPL)

代码示例:

复制代码
go 复制代码
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private async void StartButton_Click(object sender, RoutedEventArgs e)
    {
        await Task.Run(() =>
        {
            // 长时间运行的任务
            for (int i = 0; i < 100; i++)
            {
                Application.Current.Dispatcher.Invoke(() =>
                {
                    // 更新UI
                    ProgressTextBlock.Text = $"Progress: {i + 1}";
                });
                Thread.Sleep(100);
            }
        });
        ProgressTextBlock.Text = "Task completed.";
    }
}

优点:

  • 基于.NET的Task并行库,是现代异步编程的标准。

  • 支持任务取消、继续与异常处理。

缺点:

  • 需要正确处理UI线程和后台线程之间的上下文切换。

使用场景:

  • 当需要进行复杂的异步编程和任务调度时。

3. 使用Dispatcher进行线程间通信

代码示例:

复制代码
go 复制代码
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void StartButton_Click(object sender, RoutedEventArgs e)
    {
        Thread backgroundThread = new Thread(DoWork);
        backgroundThread.Start();
    }

    private void DoWork()
    {
        for (int i = 0; i < 100; i++)
        {
            Application.Current.Dispatcher.Invoke(() =>
            {
                // 更新UI
                ProgressTextBlock.Text = $"Progress: {i + 1}";
            });
            Thread.Sleep(100);
        }
        Application.Current.Dispatcher.Invoke(() =>
        {
            ProgressTextBlock.Text = "Task completed.";
        });
    }
}

优点:

  • 允许直接控制线程的创建和管理。

  • 可以精确控制UI更新。

缺点:

  • 需要手动管理线程生命周期,增加了复杂性。

使用场景:

  • 当需要直接控制后台线程的行为时。

4. 使用数据绑定和INotifyPropertyChanged接口

代码示例:

复制代码
go 复制代码
public class ViewModel : INotifyPropertyChanged
{
    private string _progress;

    public string Progress
    {
        get { return _progress; }
        set
        {
            if (_progress != value)
            {
                _progress = value;
                OnPropertyChanged(nameof(Progress));
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public void DoWork()
    {
        // 长时间运行的任务
        for (int i = 0; i < 100; i++)
        {
            Thread.Sleep(100);
            Progress = $"Progress: {i + 1}";
        }
    }
}

优点:

  • 通过数据绑定自动更新UI,减少了代码量。

  • 遵循MVVM设计模式,提高了代码的可维护性。

缺点:

  • 需要实现INotifyPropertyChanged接口,增加了实现的复杂性。

使用场景:

  • 当应用程序遵循MVVM设计模式时。

5. 使用Async/Await模式

代码示例:

复制代码
go 复制代码
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private async void StartButton_Click(object sender, RoutedEventArgs e)
    {
        await DoWorkAsync();
    }

    private async Task DoWorkAsync()
    {
        for (int i = 0; i < 100; i++)
        {
            await Task.Delay(100);
            ProgressTextBlock.Text = $"Progress: {i + 1}";
        }
        ProgressTextBlock.Text = "Task completed.";
    }
}

优点:

  • 代码简洁,易于理解和维护。

  • 自动处理线程间上下文切换。

缺点:

  • 不适用于所有类型的长时间运行任务。

使用场景:

  • 当需要在WPF应用程序中执行异步操作时。

总结

在C# WPF应用程序中,合理使用多线程技术可以显著提高应用程序的性能和用户体验。BackgroundWorker组件提供了一种简单的方式来执行后台操作;Task并行库(TPL)是现代异步编程的标准;Dispatcher是WPF中进行线程间通信的关键;数据绑定和INotifyPropertyChanged接口可以自动更新UI;Async/Await模式使得异步编程更加简单。开发者应根据具体的应用需求和场景,选择最合适的多线程实现方式。

往期精品推荐:

在国内默默无闻的.NET,在国外火的超乎想象?

C#的膨胀之路:创新还是灭亡

介绍.NET 6款好看的winform开源UI库

介绍一款最受欢迎的.NET 开源UI库

WPF第三方开源UI框架:打造独特体验的魔法师

WPF与Winform,你的选择是?

WinForm的前世今生

.NET成年了,然后呢?------编程界的逆袭传奇

相关推荐
小蜗牛慢慢爬行2 分钟前
有关异步场景的 10 大 Spring Boot 面试问题
java·开发语言·网络·spring boot·后端·spring·面试
Algorithm157612 分钟前
云原生相关的 Go 语言工程师技术路线(含博客网址导航)
开发语言·云原生·golang
shinelord明21 分钟前
【再谈设计模式】享元模式~对象共享的优化妙手
开发语言·数据结构·算法·设计模式·软件工程
呆呆小雅27 分钟前
C#关键字volatile
java·redis·c#
Monly2128 分钟前
Java(若依):修改Tomcat的版本
java·开发语言·tomcat
boligongzhu29 分钟前
DALSA工业相机SDK二次开发(图像采集及保存)C#版
开发语言·c#·dalsa
Eric.Lee202129 分钟前
moviepy将图片序列制作成视频并加载字幕 - python 实现
开发语言·python·音视频·moviepy·字幕视频合成·图像制作为视频
7yewh31 分钟前
嵌入式Linux QT+OpenCV基于人脸识别的考勤系统 项目
linux·开发语言·arm开发·驱动开发·qt·opencv·嵌入式linux
waicsdn_haha43 分钟前
Java/JDK下载、安装及环境配置超详细教程【Windows10、macOS和Linux图文详解】
java·运维·服务器·开发语言·windows·后端·jdk
_WndProc1 小时前
C++ 日志输出
开发语言·c++·算法