簡體   English   中英

UI無響應+使用BackgroundWorker C#時進度欄不起作用

[英]UI unresponsive + progress bar not working while using backgroundworker c#

我正在Visual Studio中使用WPF應用程序,我需要下載一個大文件並將其解壓縮到我的代碼中。 有人建議我使用后台工作者,但是現在當我嘗試增加進度條上的值時,它不起作用...有人可以幫忙嗎?

public void InstallVersion(string version)
    {
        string location = File.ReadAllText(@"C:\Users\" + Environment.UserName + @"\AppData\Roaming\MidnightFallsLauncher\data\locator.txt");
        location = location + @"\Versions\" + version;

        if (File.Exists(location + ".zip"))
            File.Delete(location + ".zip");

        if (Directory.Exists(location))
        {
            DirectoryInfo di = new DirectoryInfo(location);

            foreach (FileInfo file in di.GetFiles())
            {
                file.Delete();
            }
            foreach (DirectoryInfo dir in di.GetDirectories())
            {
                dir.Delete(true);
             }
        }


        if (!myWorker.IsBusy)
        {
            myWorker.RunWorkerAsync();
        }
    }

這是我的工作人員代碼

public MainWindow()
    {
        InitializeComponent();

        myWorker.DoWork += new DoWorkEventHandler(myWorker_DoWork);
        myWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(myWorker_RunWorkerCompleted);
        myWorker.ProgressChanged += new ProgressChangedEventHandler(myWorker_ProgressChanged);
        myWorker.WorkerReportsProgress = true;
        myWorker.WorkerSupportsCancellation = true;
    }

    protected void myWorker_DoWork(object sender, DoWorkEventArgs e)
    {

        string location = File.ReadAllText(@"C:\Users\" + Environment.UserName + @"\AppData\Roaming\MidnightFallsLauncher\data\locator.txt");
        location = location + @"\Versions\" + Version;

        WebClient Client = new WebClient();
        string url = "";
        string content = "";
        string downloadlink = "";

        List<string> availibleVersions = new List<string>();
        List<string> versionDownload = new List<string>();

        url = "https://midnightfalls.glitch.me/versions.html";
        content = Client.DownloadString(url);

        foreach (string line in content.Split(new string[] { "<br>", "<br />" }, StringSplitOptions.None))
        {
            if (line.Contains("0"))
            {
                availibleVersions.Add(line);
            }

        }

        url = "https://midnightfalls.glitch.me/versionslink.html";
        content = Client.DownloadString(url);

        foreach (string line in content.Split(new string[] { "<br>", "<br />" }, StringSplitOptions.None))
        {
            if (line.Contains("https"))
            {
                versionDownload.Add(line);
            }

        }

        for (var i = 0; i < availibleVersions.Count; i++)
        {
            if (availibleVersions[i] == Version)
            {
                downloadlink = versionDownload[i];
            }
        }


        Client.DownloadFile(downloadlink, location + ".zip");

        ZipFile.ExtractToDirectory(location + ".zip", location);
        File.Delete(location + ".zip");

        RunGame(Version);
    }

    protected void myWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {

    }

    protected void myWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        this.Dispatcher.Invoke(() =>
        {
            progress.Value += 10;
        });
    }

另外,當我的工作人員正在運行時,UI會凍結……我敢肯定這不會發生。

編輯: UI現在正在更新,但是進度欄仍然無法正常工作...

我敢肯定,您是在這里封鎖:

while (this.myWorker.IsBusy)
{
    this.Dispatcher.Invoke(() =>
    {
        progress.Value += 10;
    });
}

您應該在myWorker_DoWork方法中的BackgroundWorker實例上調用ReportProgress

另外,如果您使用的是.NET 4.5或更高版本,則可以完全轉儲BackgroundWorker並使用async / await模式重寫此代碼。

看起來問題在於后台線程執行工作時主線程一直在工作:

 while (this.myWorker.IsBusy)
 {
    this.Dispatcher.Invoke(() =>
    {
        progress.Value += 10;
    });
}

意味着您的主線程在后台作業正在工作時一直在做事,這就是UI不更新的原因。

您需要將進度更新移至后台工作程序(您還可以在其中設置一個實際上有意義的值,例如,指示已下載了多少個“ availableVersion”)。

希望有道理。

編輯:

假設我們將所有代碼直接放在視圖中,因此假設我們有一個名為“ progressBar”的進度條和一個名為“ btnStart”的按鈕(由背景工作人員踢出)。

下面是代碼:

private BackgroundWorker worker;

 public MainWindow()
 {
    InitializeComponent();
    this.worker = new BackgroundWorker();

    this.worker.DoWork += new DoWorkEventHandler(myWorker_DoWork);
    this.worker.RunWorkerCompleted += new 
    RunWorkerCompletedEventHandler(myWorker_RunWorkerCompleted);
    this.worker.ProgressChanged += new 
    ProgressChangedEventHandler(myWorker_ProgressChanged);
    this.worker.WorkerReportsProgress = true;
    this.worker.WorkerSupportsCancellation = true;
}

private void myWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    this.progressBar.Value = e.ProgressPercentage;
}

private void myWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
     // Whatever you need to do when finished here (alert, update a label, etc.)
}

private void myWorker_DoWork(object sender, DoWorkEventArgs e)
{
    // Just loop and report new progress. Sleep a little in between each
    // progress update so that it isn't over before we have a chance to see it.
    for(int i=0;i<100;i++)
    {
        Thread.Sleep(200);
        this.worker.ReportProgress(i);
    }
}

private void btnStart_Click(object sender, RoutedEventArgs e)
{
    this.worker.RunWorkerAsync();
}

發生的情況是后台工作人員觸發了一個事件,通知進度已更改。 主線程具有該事件的句柄,並更新進度條。 由於它是后台工作人員,因此您無需使用Dispatcher.Invoke-已經解決了。

希望該示例為您澄清一些事情。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM