簡體   English   中英

WPF進度欄-從ClickOnce升級更新進度

[英]WPF Progress Bar - Update Progress from ClickOnce Upgrade

我已經使用ClickOnce為我的應用程序部署更新了一段時間。 我很高興能夠進行改進,但對當前的進度欄感到有些沮喪。 有一點背景-我有一個XAML窗口類,稱為“ UpdateProgress”,在對該應用程序進行更新時會打開它。 這是我現在正在使用的當前代碼段,它至少會通知用戶正在進行的進度而不會凍結應用程序/崩潰,但是不會直觀地更新進度欄:

case UpdateStatuses.UpdateAvailable:
    DialogResult dialogResult = System.Windows.Forms.MessageBox.Show("An update is available. Would you like to update the application now?", "Update available", MessageBoxButtons.OKCancel);
    if (dialogResult.ToString() == "OK")
    {
        BackgroundWorker bgUpdate = new BackgroundWorker();
        UpdateProgress updateNotify = new UpdateProgress();
        bgUpdate.WorkerReportsProgress = true;
        bgUpdate.DoWork += (uptSender, uptE) => { UpdateApplication();};
        bgUpdate.ProgressChanged += (progSender, progE) => { updateNotify.updateProgress.Value = progE.ProgressPercentage; };
        bgUpdate.RunWorkerCompleted += (comSender, comE) => {
            updateNotify.Close();
            applicationUpdated();
        };
        updateNotify.Show();
        bgUpdate.RunWorkerAsync();
    }
    break;

基本上,我在上面創建了一個后台工作程序,它運行以下代碼:

private static void UpdateApplication()
{
    try
    {
        ApplicationDeployment updateCheck = ApplicationDeployment.CurrentDeployment;
        //BackgroundWorker bgWorker = new BackgroundWorker();
        //UpdateProgress updateNotify = new UpdateProgress();
        //updateCheck.UpdateProgressChanged += (s, e) =>
        //{
        //    updateNotify.updateProgress.Value = e.ProgressPercentage;

        //};
        //bgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(UpdateComponent.noteUpdates);
        //bgWorker.RunWorkerAsync();
        //updateCheck.UpdateCompleted += (s, e) =>
        //{
        //   updateNotify.Close();
        //    applicationUpdated();

        //};

        //updateNotify.Dispatcher.InvokeAsync(() =>
        // {
             //updateNotify.Show();
             updateCheck.Update();
        //});
        //return null;
    }
    catch (DeploymentDownloadException dde)
    {
        System.Windows.MessageBox.Show("Cannot install the latest version of the application. Please check your network connection, or try again later. Error: " + dde);
        //return null;
    }
}

快速說明,當前我僅創建一個名為“ updateCheck”的“ ApplicationDeployment”實例,並讓它在此線程中運行更新。 我之前嘗試過的工作是在下面加載一些注釋的代碼,只是為了查看更新時應用程序崩潰。 事實證明,使用我的應用程序的PROD實例進行調試時,是由於以下錯誤:

調用線程無法訪問該對象,因為其他線程擁有它。

現在,通過做一些挖掘,我已經看到了很多有關此的不錯的讀物。 據我了解,部分問題是我試圖從與MainWindow和其他UI類分開的靜態類中運行此代碼。 我這樣做是為了保持代碼的清潔和模塊化,但是顯然,這是有代價的。 我意識到,如果進度條位於進度條窗口的代碼后面,則可以綁定進度條的進度百分比,但是如果我試圖堅持在我所說的靜態類中運行該進度條怎么辦? 我試過使用Dispatcher方法/ BeginInvoke()之類的方法,但不幸的是最終得到了相同的結果。

有人可以給我關於如何在窗口中用ApplicationDeployment實例的更新例程的進度進度更新進度條進度的最佳建議嗎?

在此先感謝一噸。

您誤解了錯誤原因。 任何UI控件都應該從擁有它的線程中進行更新。

首先,您需要包裝的只是更新進度條的代碼行。

然后,您可以使用IProgress<T>Dispatcher兩種方式包裝呼叫。 前者非常酷,因為基本上您在調用Action<T>Progress<T>可以確保在實例化的同步上下文(例如UI線程)中運行它。 很好,因為基本上您是直接使用WPF Dispatcher將VS抽象化的。

這里有兩種截然不同的方法,首先是在調用方聲明,然后被調用方調用其Report方法,其次有效地將對UI的調用包裝在被調用方中。

這就是在bgUpdate.ProgressChanged期間要執行的bgUpdate.ProgressChanged ,需要注意。

現在,如果我是您,我會放棄BackgroundWorker來使用Task因為這是現在執行此操作的首選方法,尤其是在WPF中。

使用TaskIProgress最小示例:

碼:

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    <StackPanel>
        <Button Content="DoWork" Click="Button1_Click" />
        <ProgressBar Height="20" x:Name="ProgressBar1" Maximum="1.0"/>
    </StackPanel>
</Window>

碼:

using System;
using System.Threading.Tasks;
using System.Windows;

namespace WpfApp1
{
    public partial class MainWindow
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private async void Button1_Click(object sender, RoutedEventArgs e)
        {
            var progress = new Progress<double>(s => { ProgressBar1.Value = s; });

            await Task.Run(() => DoWork(progress));
        }

        private static async Task DoWork(IProgress<double> progress = null)
        {
            const int count = 100;

            for (var i = 0; i < count; i++)
            {
                await Task.Delay(50);

                progress?.Report(1.0d / (count - 1) * i);
            }
        }
    }
}

在此處輸入圖片說明

現在您的代碼甚至不需要了解特定於WPF的Dispatcher ,代碼可以在任何地方,可以更新任何框架。

您也可以使用Task.Run取消操作:

https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.run?view=netframework-4.7.2

暫無
暫無

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

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