Pergunta

Eu preciso ter um aplicativo de instância única (conforme este resposta ), mas ele precisa ser implantado através de um clique uma vez.

O problema é que eu preciso disso, clique uma vez não detecta automaticamente uma atualização uma tentativa de carregar uma versão mais recente, enquanto o aplicativo está sendo executado. Se estiver em execução, então eu preciso outro exemplo a ser feito ativo. Normalmente, quando a seleção de um Click Once link, a primeira coisa que ele faz é tentar encontrar uma atualização. Eu quero interceptar isso e verificar se há uma instância já em execução antes para lançar o processo de atualização normal.

Alguém sabe como isso é possível dentro de um clique Uma vez cenário de implantação?

Foi útil?

Solução

Para resolver o problema, nós construímos uma aplicação protótipo que tem a seguinte duas funcionalidades.

  1. Várias instâncias em um pc está desativado. Uma aplicação única instância é implementado através clickonce. Quando um usuário tenta iniciar uma segunda instância do aplicativo, uma mensagem irá aparecer indicando que "Outra instância já está em execução".

  2. Verifica se há uma atualização de forma assíncrona, e instala a atualização, se houver. A mensagem: "Uma atualização está disponível" irá aparecer se houver uma atualização disponível quando um usuário executa uma nova instância.

O processo para construir o aplicativo de demonstração é o seguinte:

Passo 1:. Detectar uma aplicação exemplo activo utilizando 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() );
        }
    }
}

Passo 2: atualização Handle programaticamente

Antes de fazermos isso, devemos desativar a verificação de atualização automática ClickOnce (nas Publicar - Updates ... diálogo).

Então vamos criar duas formas: UpdateProgress e Mainform, onde UpdateProgress indica progresso do download e Mainform representa a aplicação principal.

Quando um usuário executa o aplicativo, UpdateProgress será lançado em primeiro lugar, verificar se há atualizações. Ao atualizar concluída, Mainform começará e UpdateProgress serão ocultados.

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

O aplicativo funciona bem e nós esperamos que seja uma boa solução para o problema.
Um agradecimento especial a Timothy Walters para fornecer o código-fonte

Outras dicas

certeza - você pode desativar o automático a verificação de atualização ClickOnce (no Publicar -> Atualizações .. diálogo), em seguida, usar os objetos e comandos no System.Deployment.Application namespace para verificar pragmaticamente para atualizações.

Confira:

Se houver uma atualização, você pode fazer seus cheques de aplicação única instância antes de realmente atualizar, chamando:

Eu não acho que você vai ser capaz de fazê-lo bem assim como a verificação antes de executar está fora de seu código.

No entanto, você pode alterar as opções de implantação ClickOnce para verificar se há atualizações durante a execução de código.

Se você precisar de mais controle, então você pode usar o ApplicationDeployment atualização ou checkForUpdate métodos para ter absoluto sobre o processo de atualização.

http://wpfsingleinstance.codeplex.com/ na minha aplicação WPF ClickOnce com grande sucesso. Eu não precisa mudar nada.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top