初学者线程或调度员方向

时间:2015-08-18 07:24:10

标签: c# wpf multithreading webclient

我希望有人能指出我正确的方向。我想制作一个简单的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";

3 个答案:

答案 0 :(得分:6)

如果您将方法标记为 async ,则可以使用DownloadFileTaskAsync方法

await webClient.DownloadFileTaskAsync(url, csvfile)

答案 1 :(得分:0)

有很多方法可以实现它。例如:

1)如果在.Net Framework 4.5中编程,则使用async / await。它比BackgroundWorker

简单

https://msdn.microsoft.com/en-us/library/hh191443.aspx

$(document).ready(function () {

    $('.clock').each(function () {
        var clock;

        clock = $(this).FlipClock({
            clockFace: 'DailyCounter',
            autoStart: false,
            callbacks: {
                stop: function () {
                    $('.message').html('The clock has stopped!')
                }
            }
        });

        clock.setTime(220880);
        clock.setCountdown(true);
        clock.start();
    })
});

2)BackgroundWorker。此类实际上旨在进行异步操作以避免冻结UI。 见http://www.wpf-tutorial.com/misc/multi-threading-with-the-backgroundworker

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);
}

3)使用Thread类并使用Dispatcher类进行更新:

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";
}

http://www.beingdeveloper.com/use-dispatcher-in-wpf-to-build-responsive-applications

答案 2 :(得分:0)

如果您选择使用BackgroundWorker,它允许您在每个文件下载周围将这些消息输出到TextBox中。这是一个适合您要求的粗略示例。

1)在类级别,创建BackgroundWorker类的实例并将事件处理程序添加到BackgroundWorker实例的事件中:

BackgroundWorker workerDownload = new BackgroundWorker();
workerDownload.WorkerReportsProgress = true;
workerDownload.DoWork += workerDownload_DoWork;
workerDownload.ProgressChanged += workerDownload_ProgressChanged;
workerDownload.RunWorkerCompleted += workerDownload_RunWorkerCompleted;

2)为后台工作人员的DoWork事件创建一个事件处理程序:

  

DoWork事件处理程序是您运行耗时操作的地方   在后台线程。传递给后台的任何值   操作在DoWorkEventArgs的Argument属性中传递   传递给事件处理程序的对象。

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事件创建一个事件处理程序:

  

在ProgressChanged事件处理程序中,添加代码以指示   进度,例如更新用户界面。

private void workerDownload_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    tbOutput.Text += e.UserState.ToString();
}

4)为RunWorkerCompleted事件创建一个事件处理程序:

  

后台工作者具有RunWorkerCompleted事件   完成。

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);