我已经实现了一个功能应用程序,它可以同时解析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方法,我必须做错了...我是线程新手。
答案 0 :(得分:2)
如果您不熟悉线程,我认为最简单的方法是使用BackgroundWorker:
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仍然响应,那么您的代码问题就会减少。 (而不是尝试一次运行一个线程并处理多个网页)