初学者线程或调度程序方向
Beginner Thread or Dispatcher direction
我希望有人能指出我正确的方向。我想制作一个简单的 WPF 应用程序,它有一个按钮和一个文本框。我单击该按钮,它开始循环下载一堆文件。我似乎无法弄清楚如何不让下载停止 UI 更新。据我所知,我可能不得不使用一些线程代码;但到目前为止,我发现和尝试过的所有示例都不适合我。任何关于我应该在哪里寻找和学习的帮助或指导都会很棒。我似乎无法弄清楚如何在每次文件下载时输出那些 textbox.text 消息。
foreach (var ticker in tickers)
{
var url = string.Format(urlPrototype, ticker, startMonth, startDay, startYear, finishMonth, finishDay, finishYear, "d");
var csvfile = directory + "\" + ticker.ToUpper() + ".csv";
tbOutput.Text += "Starting Download of : " + ticker + "\n";
webClient.DownloadFile(url, csvfile);
tbOutput.Text += "End Download of : " + ticker + "\n";
numStocks++;
}
tbOutput.Text += "Total stocks downloaded = " + numStocks + "\n";
如果将方法标记为 async,则可以使用 DownloadFileTaskAsync
方法
await webClient.DownloadFileTaskAsync(url, csvfile)
有很多方法可以实现。例如:
1) 如果您在 .Net Framework 4.5 中编程,则使用 async/await。它比 BackgroundWorker
更简单
https://msdn.microsoft.com/en-us/library/hh191443.aspx
private async void button_Click(object sender, RoutedEventArgs e)
{
Uri someUrl=new Uri(@"http://dotnetperls.com");
WebClient webClient=new WebClient();
await webClient.DownloadFileTaskAsync(someUrl, csvFile);
}
2) 背景工作者。这个class其实是为了做异步操作,避免卡顿UI。
参见 http://www.wpf-tutorial.com/misc/multi-threading-with-the-backgroundworker
public partial class MainWindow : Window
{
BackgroundWorker bw;
public MainWindow()
{
InitializeComponent();
bw = new BackgroundWorker();
bw.DoWork += bw_DoWok;
bw.RunWorkerCompleted += bw_RunWorkerCompleted;
}
}
void bw_RunWorkerComleted(object sender, RunWorkerCompletedEventAgs e)
{
MessageBox.Show("The result is " + e.Result.ToString());
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
foreach (var ticker in tickers)
{
var url = string.Format(urlPrototype, ticker, startMonth, startDay, startYear, finishMonth, finishDay, finishYear, "d");
var csvfile = directory + "\" + ticker.ToUpper() + ".csv";
webClient.DownloadFile(url, csvfile);
numStocks++;
}
e.Result = "End Of Download ";
}
private void button_Click(object sender, RoutedEventArgs e)
{
bw.RunWorkerAsync();
tbOutput.Text += "Starting Download of : " + ticker + "\n";
}
3) 使用 Thread class 并使用 Dispatcher class 更新:
ThreadStart job = new ThreadStart(() =>
{
foreach (var ticker in tickers)
{
var url = string.Format(urlPrototype, ticker, startMonth, startDay, startYear, finishMonth, finishDay, finishYear, "d");
var csvfile = directory + "\" + ticker.ToUpper() + ".csv";
webClient.DownloadFile(url, csvfile);
numStocks++;
}
Dispatcher.BeginInvoke((Action)(()=> tbOutput.Text += "End Download of : " + ticker + "\n";}));
});
Thread thread = new Thread(job);
thread.Start();
http://www.beingdeveloper.com/use-dispatcher-in-wpf-to-build-responsive-applications
如果您选择使用 BackgroundWorker,它允许您将这些消息输出到每个文件下载周围的文本框中。这是根据您的要求改编的粗略示例。
1) 在 class 级别,创建 BackgroundWorker 实例 class 并将事件处理程序添加到 BackgroundWorker 实例的事件中:
BackgroundWorker workerDownload = new BackgroundWorker();
workerDownload.WorkerReportsProgress = true;
workerDownload.DoWork += workerDownload_DoWork;
workerDownload.ProgressChanged += workerDownload_ProgressChanged;
workerDownload.RunWorkerCompleted += workerDownload_RunWorkerCompleted;
2) 为后台工作者的 DoWork 事件创建一个事件处理器:
The DoWork event handler is where you run the time-consuming operation
on the background thread. Any values that are passed to the background
operation are passed in the Argument property of the DoWorkEventArgs
object that is passed to the event handler.
private void workerDownload_DoWork(object sender, DoWorkEventArgs e)
{
foreach (var ticker in tickers)
{
// you can pass the required info as argument:
string[] arrArg = (string[])e.Argument;
string theUrl = arrArg[0];
string directory = arrArg[1];
var url = string.Format(theUrl, ticker);
var csvfile = directory + "\" + ticker.ToUpper() + ".csv";
// perform the download operation and report progress:
workerDownload.ReportProgress(0, "Starting Download of : " + ticker + "\n");
webClient.DownloadFile(url, csvfile);
workerDownload.ReportProgress(100, "End Download of : " + ticker + "\n");
numStocks++;
}
}
3) 为后台工作者的 ProgressChanged 事件创建一个事件处理器:
In the ProgressChanged event handler, add code to indicate the
progress, such as updating the user interface.
private void workerDownload_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
tbOutput.Text += e.UserState.ToString();
}
4) 为 RunWorkerCompleted 事件创建事件处理程序:
The RunWorkerCompleted event is raised when the background worker has
completed.
private void workerDownload_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
tbOutput.Text += "Total stocks downloaded = " + numStocks + "\n";
}
5) 通过调用 RunWorkerAsync 方法启动 运行 后台操作:
int numStocks = 0;
string strDirectory = "<a_directory>";
string strUrl = string.Format(urlPrototype, startMonth, startDay, startYear, finishMonth, finishDay, finishYear, "d");
string[] args = new string[2] { strUrl, strDirectory };
workerDownload.RunWorkerAsync(args);
我希望有人能指出我正确的方向。我想制作一个简单的 WPF 应用程序,它有一个按钮和一个文本框。我单击该按钮,它开始循环下载一堆文件。我似乎无法弄清楚如何不让下载停止 UI 更新。据我所知,我可能不得不使用一些线程代码;但到目前为止,我发现和尝试过的所有示例都不适合我。任何关于我应该在哪里寻找和学习的帮助或指导都会很棒。我似乎无法弄清楚如何在每次文件下载时输出那些 textbox.text 消息。
foreach (var ticker in tickers)
{
var url = string.Format(urlPrototype, ticker, startMonth, startDay, startYear, finishMonth, finishDay, finishYear, "d");
var csvfile = directory + "\" + ticker.ToUpper() + ".csv";
tbOutput.Text += "Starting Download of : " + ticker + "\n";
webClient.DownloadFile(url, csvfile);
tbOutput.Text += "End Download of : " + ticker + "\n";
numStocks++;
}
tbOutput.Text += "Total stocks downloaded = " + numStocks + "\n";
如果将方法标记为 async,则可以使用 DownloadFileTaskAsync
方法
await webClient.DownloadFileTaskAsync(url, csvfile)
有很多方法可以实现。例如:
1) 如果您在 .Net Framework 4.5 中编程,则使用 async/await。它比 BackgroundWorker
更简单https://msdn.microsoft.com/en-us/library/hh191443.aspx
private async void button_Click(object sender, RoutedEventArgs e)
{
Uri someUrl=new Uri(@"http://dotnetperls.com");
WebClient webClient=new WebClient();
await webClient.DownloadFileTaskAsync(someUrl, csvFile);
}
2) 背景工作者。这个class其实是为了做异步操作,避免卡顿UI。 参见 http://www.wpf-tutorial.com/misc/multi-threading-with-the-backgroundworker
public partial class MainWindow : Window
{
BackgroundWorker bw;
public MainWindow()
{
InitializeComponent();
bw = new BackgroundWorker();
bw.DoWork += bw_DoWok;
bw.RunWorkerCompleted += bw_RunWorkerCompleted;
}
}
void bw_RunWorkerComleted(object sender, RunWorkerCompletedEventAgs e)
{
MessageBox.Show("The result is " + e.Result.ToString());
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
foreach (var ticker in tickers)
{
var url = string.Format(urlPrototype, ticker, startMonth, startDay, startYear, finishMonth, finishDay, finishYear, "d");
var csvfile = directory + "\" + ticker.ToUpper() + ".csv";
webClient.DownloadFile(url, csvfile);
numStocks++;
}
e.Result = "End Of Download ";
}
private void button_Click(object sender, RoutedEventArgs e)
{
bw.RunWorkerAsync();
tbOutput.Text += "Starting Download of : " + ticker + "\n";
}
3) 使用 Thread class 并使用 Dispatcher class 更新:
ThreadStart job = new ThreadStart(() =>
{
foreach (var ticker in tickers)
{
var url = string.Format(urlPrototype, ticker, startMonth, startDay, startYear, finishMonth, finishDay, finishYear, "d");
var csvfile = directory + "\" + ticker.ToUpper() + ".csv";
webClient.DownloadFile(url, csvfile);
numStocks++;
}
Dispatcher.BeginInvoke((Action)(()=> tbOutput.Text += "End Download of : " + ticker + "\n";}));
});
Thread thread = new Thread(job);
thread.Start();
http://www.beingdeveloper.com/use-dispatcher-in-wpf-to-build-responsive-applications
如果您选择使用 BackgroundWorker,它允许您将这些消息输出到每个文件下载周围的文本框中。这是根据您的要求改编的粗略示例。
1) 在 class 级别,创建 BackgroundWorker 实例 class 并将事件处理程序添加到 BackgroundWorker 实例的事件中:
BackgroundWorker workerDownload = new BackgroundWorker();
workerDownload.WorkerReportsProgress = true;
workerDownload.DoWork += workerDownload_DoWork;
workerDownload.ProgressChanged += workerDownload_ProgressChanged;
workerDownload.RunWorkerCompleted += workerDownload_RunWorkerCompleted;
2) 为后台工作者的 DoWork 事件创建一个事件处理器:
The DoWork event handler is where you run the time-consuming operation on the background thread. Any values that are passed to the background operation are passed in the Argument property of the DoWorkEventArgs object that is passed to the event handler.
private void workerDownload_DoWork(object sender, DoWorkEventArgs e)
{
foreach (var ticker in tickers)
{
// you can pass the required info as argument:
string[] arrArg = (string[])e.Argument;
string theUrl = arrArg[0];
string directory = arrArg[1];
var url = string.Format(theUrl, ticker);
var csvfile = directory + "\" + ticker.ToUpper() + ".csv";
// perform the download operation and report progress:
workerDownload.ReportProgress(0, "Starting Download of : " + ticker + "\n");
webClient.DownloadFile(url, csvfile);
workerDownload.ReportProgress(100, "End Download of : " + ticker + "\n");
numStocks++;
}
}
3) 为后台工作者的 ProgressChanged 事件创建一个事件处理器:
In the ProgressChanged event handler, add code to indicate the progress, such as updating the user interface.
private void workerDownload_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
tbOutput.Text += e.UserState.ToString();
}
4) 为 RunWorkerCompleted 事件创建事件处理程序:
The RunWorkerCompleted event is raised when the background worker has completed.
private void workerDownload_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
tbOutput.Text += "Total stocks downloaded = " + numStocks + "\n";
}
5) 通过调用 RunWorkerAsync 方法启动 运行 后台操作:
int numStocks = 0;
string strDirectory = "<a_directory>";
string strUrl = string.Format(urlPrototype, startMonth, startDay, startYear, finishMonth, finishDay, finishYear, "d");
string[] args = new string[2] { strUrl, strDirectory };
workerDownload.RunWorkerAsync(args);