Domanda

Devo avere un'applicazione a istanza singola (come da questo risposta ), ma deve essere distribuita tramite clic una volta.

Il problema è che richiedo che il clic una volta non rilevi automaticamente un aggiornamento nel tentativo di caricare una versione più recente mentre l'applicazione è in esecuzione. Se è in esecuzione, allora ho bisogno che l'altra istanza sia resa attiva. Di solito, quando si seleziona un collegamento Fai clic una volta, la prima cosa che fa è tentare di trovare un aggiornamento. Voglio intercettarlo e verificare se un'istanza già in esecuzione precedente per avviare il normale processo di aggiornamento.

Qualcuno sa come sia possibile in uno scenario di distribuzione Click Once?

È stato utile?

Soluzione

Per affrontare il problema, abbiamo creato un'applicazione prototipo che ha le seguenti due funzionalità.

  1. Più istanze su un PC sono disabilitate. Un'applicazione a singola istanza viene distribuita tramite clickonce. Quando un utente tenta di avviare una seconda istanza dell'app, viene visualizzato un messaggio che indica che " Un'altra istanza è già in esecuzione " ;.

  2. Verifica un aggiornamento in modo asincrono e installa l'aggiornamento se ne esiste uno. Un messaggio: " Un aggiornamento è disponibile " verrà visualizzato se è disponibile un aggiornamento quando un utente esegue una nuova istanza.

Il processo per creare l'applicazione demo è il seguente:

Passaggio 1: rileva un'applicazione di istanza attiva utilizzando la classe Mutex.

namespace ClickOnceDemo
{
    static class Program
    {
        /// summary>
        /// The main entry point for the application.
        /// /summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault( false );
            bool ok;
            var m = new System.Threading.Mutex( true, "Application", out ok );
            if ( !ok )
            {
                MessageBox.Show( "Another instance is already running.", ApplicationDeployment.CurrentDeployment.CurrentVersion.ToString() );
                return;
            }
           Application.Run( new UpdateProgress() );
        }
    }
}

Passaggio 2: gestisci l'aggiornamento a livello di codice

Prima di farlo, dovremmo disabilitare il controllo automatico degli aggiornamenti ClickOnce (nella finestra di dialogo Pubblica - Aggiornamenti ...).

Quindi creiamo due moduli: UpdateProgress e mainForm, dove UpdateProgress indica l'avanzamento del download e mainForm rappresenta l'applicazione principale.

Quando un utente esegue l'applicazione, updateProgress verrà avviato innanzitutto per verificare la presenza di aggiornamenti. Al termine dell'aggiornamento, mainForm verrà avviato e updateProgress verrà nascosto.

namespace ClickOnceDemo
{
public partial class UpdateProgress : Form
 {
  public UpdateProgress()
        {
            InitializeComponent();
            Text = "Checking for updates...";

            ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment;
            ad.CheckForUpdateCompleted += OnCheckForUpdateCompleted;
            ad.CheckForUpdateProgressChanged += OnCheckForUpdateProgressChanged;

            ad.CheckForUpdateAsync();
       }

        private void OnCheckForUpdateProgressChanged(object sender, DeploymentProgressChangedEventArgs e)
        {
            lblStatus.Text = String.Format( "Downloading: {0}. {1:D}K of {2:D}K downloaded.", GetProgressString( e.State ), e.BytesCompleted / 1024, e.BytesTotal / 1024 );
            progressBar1.Value = e.ProgressPercentage;
        }

        string GetProgressString( DeploymentProgressState state )
        {
            if ( state == DeploymentProgressState.DownloadingApplicationFiles )
            {
                return "application files";
            }
            if ( state == DeploymentProgressState.DownloadingApplicationInformation )
            {
                return "application manifest";
            }
            return "deployment manifest";
        }

        private void OnCheckForUpdateCompleted(object sender, CheckForUpdateCompletedEventArgs e)
        {
            if ( e.Error != null )
            {
                MessageBox.Show( "ERROR: Could not retrieve new version of the application. Reason: \n" + e.Error.Message + "\nPlease report this error to the system administrator." );
                return;
            }
            if ( e.Cancelled )
            {
                MessageBox.Show( "The update was cancelled." );
            }

            // Ask the user if they would like to update the application now.
            if ( e.UpdateAvailable )
            {
                if ( !e.IsUpdateRequired )
                {
                    long updateSize = e.UpdateSizeBytes;
                    DialogResult dr = MessageBox.Show( string.Format("An update ({0}K) is available. Would you like to update the application now?", updateSize/1024), "Update Available", MessageBoxButtons.OKCancel );
                    if ( DialogResult.OK == dr )
                    {
                        BeginUpdate();
                    }
                }
                else
                {
                    MessageBox.Show( "A mandatory update is available for your application. We will install the update now, after which we will save all of your in-progress data and restart your application." );
                    BeginUpdate();
                }
            }
            else
            {
                ShowMainForm();
            }
        }

        // Show the main application form
        private void ShowMainForm()
        {
            MainForm mainForm = new MainForm ();
            mainForm.Show();
            Hide();
        }

        private void BeginUpdate()
        {
            Text = "Downloading update...";
            ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment;
            ad.UpdateCompleted += ad_UpdateCompleted;
            ad.UpdateProgressChanged += ad_UpdateProgressChanged;

            ad.UpdateAsync();
        }

        void ad_UpdateProgressChanged( object sender, DeploymentProgressChangedEventArgs e )
        {
            String progressText = String.Format( "{0:D}K out of {1:D}K downloaded - {2:D}% complete", e.BytesCompleted / 1024, e.BytesTotal / 1024, e.ProgressPercentage );
            progressBar1.Value = e.ProgressPercentage;
            lblStatus.Text = progressText;
        }

        void ad_UpdateCompleted( object sender, AsyncCompletedEventArgs e )
        {
            if ( e.Cancelled )
            {
                MessageBox.Show( "The update of the application's latest version was cancelled." );
                return;
            }
            if ( e.Error != null )
            {
                MessageBox.Show( "ERROR: Could not install the latest version of the application. Reason: \n" + e.Error.Message + "\nPlease report this error to the system administrator." );
                return;
            }

            DialogResult dr = MessageBox.Show( "The application has been updated. Restart? (If you do not restart now, the new version will not take effect until after you quit and launch the application again.)", "Restart Application", MessageBoxButtons.OKCancel );
            if ( DialogResult.OK == dr )
            {
                Application.Restart();
            }
            else
            {
                ShowMainForm();
            }
        }
    }
}

L'applicazione funziona bene e speriamo che sia una buona soluzione al problema.
Un ringraziamento speciale a Timothy Walters per aver fornito il codice sorgente

Altri suggerimenti

Sicuro - puoi disabilitare il controllo automatico degli aggiornamenti ClickOnce (nella finestra di dialogo Pubblica - > Aggiornamenti ..), quindi usa gli oggetti e i comandi nella Spazio dei nomi System.Deployment.Application per verificare pragmaticamente la presenza di aggiornamenti.

Check out:

Se è presente un aggiornamento, è possibile eseguire i controlli dell'applicazione a istanza singola prima dell'aggiornamento effettivo, chiamando:

Non credo che sarai in grado di farlo in questo modo poiché il controllo prima dell'esecuzione è al di fuori del tuo codice.

Tuttavia, è possibile modificare le opzioni di distribuzione clickonce per verificare la presenza di aggiornamenti durante l'esecuzione del codice.

Se hai bisogno di maggiore controllo, puoi usare ApplicationDeployment Update o CheckForUpdate per avere assoluto durante il processo di aggiornamento.

Ho usato http://wpfsingleinstance.codeplex.com/ nella mia applicazione WOF ClickOnce con grande successo. Non ho dovuto cambiare nulla.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top