在c#中对现有代码实现多线程的最简单方法是什么?

时间:2011-01-08 01:38:33

标签: c# wpf multithreading

我已经实现了一个功能应用程序,它可以同时解析26页的html,以生成包含在网页上的数据的xml文件。我需要实现一个线程,以便此方法可以在后台运行,而不会导致我的应用程序似乎没有响应。

其次,我有另一个与第一个函数分离的函数,它比较两个xml文件以产生第三个,然后转换第三个xml文件以使用XSLT生成一个html页面。这必须在一个线程上,我可以点击取消来停止线程而不会崩溃应用程序。

在VS 2010中使用WPF表单执行此操作的最简单方法是什么?

我选择使用BackgroundWorker。

BackgroundWorker实施:

public partial class MainWindow : Window
    {
        private BackgroundWorker bw = new BackgroundWorker();

        public MainWindow()
        {
            InitializeComponent();
            bw.WorkerReportsProgress = true;
            bw.DoWork += new DoWorkEventHandler(bw_DoWork);
            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            this.LoadFiles();
        }

        private void btnCompare_Click(object sender, EventArgs e)
        {
            if (bw.IsBusy != true)
            {
                progressBar2.IsIndeterminate = true;
                // Start the asynchronous operation.
                bw.RunWorkerAsync();
            }

        }

        private void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            StatsProcessor proc = new StatsProcessor();
            if (lstStatsBox1.SelectedItem != null)
                if (lstStatsBox2.SelectedItem != null)
                    proc.CompareStats(lstStatsBox1.SelectedItem.ToString(), lstStatsBox2.SelectedItem.ToString());
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            progressBar2.IsIndeterminate = false;
            progressBar2.Value = 100;
        }

我已经开始使用bgworker解决方案了,但是当点击btnCompare时似乎从未调用bw_DoWork方法,我必须做错了...我是线程新手。

3 个答案:

答案 0 :(得分:2)

如果您不熟悉线程,我认为最简单的方法是使用BackgroundWorker

  • 它使用另一个线程:您可以在应用程序保持响应的同时异步执行HTML解析
  • 支持取消:您可以取消XML转换为HTML

BackgroundWorker是事件驱动的,因此如果您是多线程的新手,可以更轻松地取得成功。 .NET 4任务库更灵活,但更多涉及利用UI更新。

示例:

BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler((o, args) =>
{
    //Long running stuff here       
    Thread.Sleep(10000);
    string result = "Hi UI!";
    args.Result = result;
});

worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler((o, args) =>
{
    if (args.Result != null)
    {
        SomeTextBox.Text = args.Result;
    }
});

worker.RunWorkerAsync();

答案 1 :(得分:1)

由于您使用的是.NET 4和VS2010,我将使用任务并行库。这是一个示例,显示了如何后台任务和将UI更新编组回GUI的基础知识。我认为你需要使用BlockingCollection来实现第二部分。

有一篇很好的博客文章讨论了链接任务和支持取消: http://blogs.msdn.com/b/csharpfaq/archive/2010/08/12/blocking-collection-and-the-producer-consumer-problem.aspx

以下是没有后台工作人员的背面接地示例

MainWindow.xaml - 它只是一个带有状态标签的窗口。获得重点所需的最小值:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Width="378" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" d:DesignHeight="94" SizeToContent="Height">
    <Grid>
        <StackPanel>
            <Button Click="Button_Click">Press Me</Button>
            <StatusBar>
                <Label Name="TheLabel" Content="Status" />
            </StatusBar>
        </StackPanel>
    </Grid>
</Window>

以下是代码背后:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Threading.Tasks;

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        // Dispatchers are an easy way to update the UI from a background thread
        private System.Windows.Threading.Dispatcher Dispatcher;

        // the Current Task - think of this as your background worker
        private Task CurrentTask;


        public MainWindow()
        {
            InitializeComponent();

            // this line needs to run on the main thread.

            Dispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher;
        }

        private void UpdateStatus(string msg)
        {
            // marshall the call back to the main thread
            Dispatcher.Invoke( new Action( () => TheLabel.Content = msg ));
        }

        // we're going to calculate the average of a sh*tload (technical term) of numbers
        private void DoSomeWork()
        {
            // update the UI
            UpdateStatus("Doing Work");

            Random r = new Random();
            int max = r.Next(100000000, 1000000000);
            double avg = Enumerable.Range(0, max).Average();

            // update the UI
            UpdateStatus(string.Format("Done - Average = {0}", avg));
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            // make sure the current task isn't already running
            if (CurrentTask != null && CurrentTask.IsCompleted == false)
            {
                MessageBox.Show("Wait");
                return;
            }

            // start a new one
            CurrentTask = Task.Factory.StartNew(() =>
                {
                    DoSomeWork();
                });
        }
    }
}

答案 2 :(得分:0)

您可以使用Threadpools轻松执行多线程处理。但是,您遇到的麻烦和问题将与生成此XML文件的代码有关。如果您将此代码限制为一次只运行一个线程 - 但您的UI仍然响应,那么您的代码问题就会减少。 (而不是尝试一次运行一个线程并处理多个网页)