Как я могу создать одно приложение с помощью Click Once?

Мне нужно иметь одно приложение экземпляра (в соответствии с этим answer), но его нужно развернуть через клик один раз.

Проблема в том, что я требую, чтобы один клик однажды не обнаружил автоматическое обнаружение попытки загрузки более новой версии во время работы приложения. Если он запущен, мне нужен другой экземпляр, который будет активирован. Обычно, при выборе ссылки Click Once, самое первое, что он делает, это попытка найти обновление. Я хочу перехватить это и проверить уже запущенный экземпляр предыдущий, чтобы запустить обычный процесс обновления.

Кто-нибудь знает, как это возможно в сценарии Click Once после развертывания?

Ответы

Ответ 1

Чтобы решить эту проблему, мы создали прототип приложения, которое имеет следующие две функции.

  • Несколько экземпляров на одном компьютере отключены. Одно приложение экземпляра развертывается через clickonce. Когда пользователь пытается запустить второй экземпляр приложения, появится сообщение, указывающее, что "Другой экземпляр уже запущен".

  • Проверяет наличие асинхронного обновления и устанавливает обновление, если оно существует. Появится сообщение: "Доступно обновление", если доступно обновление, когда пользователь запускает новый экземпляр.

Процесс создания демонстрационного приложения выглядит следующим образом:

Шаг 1: Обнаружение активного приложения экземпляра с использованием класса 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() );
        }
    }
}

Шаг 2: Обработать обновление программно

Прежде чем мы это сделаем, мы должны отключить автоматическую проверку обновлений ClickOnce (в диалоговом окне Publish - Updates...).

Затем мы создаем две формы: UpdateProgress и mainForm, где UpdateProgress указывает процесс загрузки, а mainForm представляет основное приложение.

Когда пользователь запускает приложение, сначала запускается updateProgress, чтобы проверить наличие обновлений. По завершении обновления mainForm запустится и updateProgress будет скрыт.

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

Приложение работает хорошо, и мы надеемся, что это хорошее решение проблемы.
Особая благодарность Тимоти Уолтерс за предоставление исходного кода

Ответ 2

Конечно - вы можете отключить автоматическую проверку обновлений ClickOnce (в диалоговом окне "Опубликовать → Обновления" ), затем использовать объекты и команды в System.Deployment.Application, чтобы прагматически проверять наличие обновлений.

Отъезд:

Если есть обновление, вы можете выполнить проверку отдельных экземпляров приложения перед фактическим обновлением, вызвав:

Ответ 3

Я не думаю, что вы сможете сделать это совершенно так, как проверка перед запуском вне вашего кода.

Однако вы можете изменить параметры развертывания clickonce для проверки обновлений во время выполнения кода.

Если вам нужно больше управления, вы можете использовать Обновление ApplicationDeployment или CheckForUpdate, чтобы иметь абсолютный над процессом обновления.

Ответ 4

Я использовал http://wpfsingleinstance.codeplex.com/ в моем приложении WPF ClickOnce с большим успехом. Мне ничего не нужно было менять.