【问题标题】:WPF UI FreezingWPF UI 冻结
【发布时间】:2015-01-16 11:02:01
【问题描述】:

我正在尝试更新 UI 上的 2 个标签和 2 个进度条。 但是它不起作用,表格只是冻结并且在保存结束之前没有任何反应。 在 Windows 窗体中,我习惯于使用 Invoke 并使其更新。如何在 WPF 中实现更新?

谢谢!

public void EncryptFiles(string saveFileLocation, string saveFileTitle, string saveFileExtension)
{

    using (ZipFile zip = new ZipFile())
    {


        zip.Password = passwordField1.Password;
        zip.Encryption = EncryptionAlgorithm.WinZipAes256;
        foreach (File file in dataStorage.listOfFiles)
        {

            zip.AddFile(file.fileLocation, String.Empty);
        }
        zip.SaveProgress += SaveProgress;


        zip.Save(System.IO.Path.Combine(saveFileLocation, saveFileTitle + saveFileExtension));

    }

}


public void SaveProgress(object sender, SaveProgressEventArgs e)
{
    if (e.EventType == ZipProgressEventType.Saving_Started)
    {
        System.Windows.Forms.MessageBox.Show("Begin Saving: " + e.ArchiveName);
    }
    else if (e.EventType == ZipProgressEventType.Saving_BeforeWriteEntry)
    {

        labelCompressionStatus.Content = "Writing: " + e.CurrentEntry.FileName + " (" + (e.EntriesSaved + 1) + "/" + e.EntriesTotal + ")";
        labelFilename.Content= "Filename:" + e.CurrentEntry.FileName;
        progressBar2.Maximum = e.EntriesTotal;
        progressBar2.Value = e.EntriesSaved + 1;


    }
    else if (e.EventType == ZipProgressEventType.Saving_EntryBytesRead)
    {
        progressBar1.Value = (int)((e.BytesTransferred * 100) / e.TotalBytesToTransfer);  
    }
    else if (e.EventType == ZipProgressEventType.Saving_Completed)
    {
        System.Windows.Forms.MessageBox.Show("Done: " + e.ArchiveName);
    }
}

【问题讨论】:

标签: c# wpf user-interface


【解决方案1】:
Dispatcher.Invoke(new Action(() => { 
 // code here for updating GUI
 }), DispatcherPriority.ContextIdle);

找到了,对我有用,谢谢大家

【讨论】:

  • 如果这对您有用,您应该接受 Xcelled194 的回答 - 他在近半小时前告诉您这样做。
  • 结合后台工作者,这对我有用。谢谢!
【解决方案2】:

除非您在单独的线程中执行代码,否则在您完成方法之前,UI 不会更新。更改progressBar1 的值最终不会有任何影响,因为在所有工作完成之前更改将不可见。最简单的方法可能是将EncryptFiles 的工作分配给BackgroundWorker:

BackgroundWorker bw = new BackgroundWorker() { WorkerReportsProgress = true };
bw.DoWork += EncryptFiles;
bw.ProgressChanged += ReportEncryptSaveProgress;

然后,保持对bw 的引用,并在每次更新任务时调用bw.ReportProgress(),将完成百分比传递给方法。鉴于 ReportProgress 发生在 UI 线程上,您应该将您的更新放到您的 ProgressBars 中,并且用户应该会看到保存的进度。

请注意,我不能 100% 确定您希望如何将您的工作转移到 BackgroundWorker - 我不确定我知道 ZipFile 对象的事件是如何工作的,因此您可能必须使用它少量。考虑到我假设您无法更改 SaveProgress 的方法签名,最终将 BackgroundWorker 设置为您的类的字段而不是尝试将其传递给 SaveProgress 可能会更容易。

您可以使用 Dispatcher 完成 UI 更新,但您的 UI 在整个操作过程中仍会完全锁定,这通常是可以避免的。

【讨论】:

  • 啊,你是对的。我以为他已经在一个单独的线程上运行它,因为他说他在 WinForms 中做过类似的事情。
  • @Xcelled194 这是我的一个假设,但似乎他不在另一个线程上。否则我希望他会问InvalidCrossThreadAccess,而不是为什么他的 UI 什么都不做。
  • 也许他得到了那个错误并解决了它?虽然我不知道您如何没有 Dispatcher 来解决它......我想我们将不得不等待,看看 OP 说了什么。
【解决方案3】:

编辑:我的回答仅适用于您在不同于 UI 线程的线程上运行解压缩操作(不必是后台工作人员)。否则,furkle 的答案就是你想要的。

查看 WPF dispatcher。它是为这种用例设计的,大致类似于 Winforms 中的Control.Invoke()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-22
    • 2018-12-24
    • 1970-01-01
    • 1970-01-01
    • 2016-07-30
    • 2018-12-22
    • 2016-05-12
    相关资源
    最近更新 更多