Самый верхний вызов Windows.Form из рабочего потока не работает, когда ClickOnce включен и опубликован - PullRequest
1 голос
/ 28 марта 2012

У меня есть основной поток, который является формой, которая запускает другое приложение, в данном случае Блокнот, затем я запускаю BackgroundWorker, который ожидает закрытия Блокнота. Когда он закрыт, BackgroundWorker показывает другую форму, которая должна отображаться пользователю. Эта форма должна быть немодальной, чтобы пользователь мог нажимать на некоторые кнопки в диалоговом окне основного потока. Проблема в том, что эта форма (Form2, из BackgroundWorker) НЕ является TopMost, хотя я установил для нее значение true. Это работает, когда я нажимаю F5, но когда я публикую, как приложение ClickOnce, на моем сервере, form2 больше не TopMost. Мне надоел Form2.Topmost = true, BringToFront, Activate, "MakeTopMost" от Какой мощный способ заставить форму выдвинуть фронт? .... похоже, ничего не работает.

Я даже пытался получить дескриптор главной формы и использовать его в качестве родителя для form2, но я получаю "InvalidOperationException: операция между потоками недопустима: доступ к элементу управления Form2 осуществляется из потока, отличного от нить, в которой он был создан. "

Вот фрагмент кода:

public partial class Form1 : Form
{
    System.Diagnostics.Process p = new System.Diagnostics.Process();
    private BackgroundWorker endApplicationBackgroundWorker= new BackgroundWorker();

    public Form1(string[] args)
    {
        endApplicationBackgroundWorker.DoWork += new DoWorkEventHandler(endApplicationBackgroundWorker_DoWork);

        p.StartInfo.FileName = "notepad";
        p.Start();

        endApplicationBackgroundWorker.RunWorkerAsync();

        //Quit here so we can accept user inputs (button pushes ..)
    }

    private void endApplicationBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        p.WaitForExit();

        Form2 form2 = new Form2();
        form2.TopMost = true;

        System.Diagnostics.Process[] procs = System.Diagnostics.Process.GetProcessesByName(form1ProcessName);
        if (procs.Length != 0)
        {
            IntPtr hwnd = procs[0].MainWindowHandle;
            if (form2.ShowDialog(new WindowWrapper(hwnd)) == DialogResult.OK)
            {
                // process stuff
            }
        }

        this.Close();
    }
}

Есть еще идеи? Или кто-то может исправить мой код выше? Я занимаюсь этим вопросом уже несколько недель и растерялся.

Спасибо!

Ответы [ 2 ]

1 голос
/ 28 марта 2012

Любая работа, выполняемая вами в методе BackgroundWorker's DoWork после вызова процедуры RunWorkerAsync, НЕ выполняется в потоке пользовательского интерфейса, но ваш код создает форму в фоновом режиме.

Формы являются элементами пользовательского интерфейса, поэтому это не будет работать:

private void endApplicationBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
  Form2 form2 = new Form2();
  form2.TopMost = true;
  // etc..
  if (form2.ShowDialog(new WindowWrapper(hwnd)) == DialogResult.OK)
  {
    // process stuff
  }
}

Из комментариев вы должны подписаться на событие RunWorkerCompleted, чтобы показать свою вторую форму. Кроме того, вы также не можете вызвать метод Close, поскольку пытаетесь поддерживать форму Form2 без вызова ShowDialog, поэтому попробуйте подписаться на событие Form_Closing() второй формы, чтобы уведомить, когда основная форма должна быть закрыта. тоже:

public Form1(string[] args)
{
  endApplicationBackgroundWorker.DoWork += 
    new DoWorkEventHandler(endApplicationBackgroundWorker_DoWork);
  endApplicationBackgroundWorker.RunWorkerCompleted += 
    new RunWorkerCompletedEventHandler(endApplicationBackgroundWorker_RunWorkerCompleted);

  p.StartInfo.FileName = "notepad";
  endApplicationBackgroundWorker.RunWorkerAsync();
}

private void endApplicationBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
  p.Start();
  p.WaitForExit();
}

private void endApplicationBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
  Form2 form2 = new Form2();
  form2.TopMost = true;
  form2.FormClosing += new FormClosingEventHandler(form2_FormClosing);    
  form2.Show(this);
}

private void form2_FormClosing(object sender, FormClosingEventArgs e)
{
  this.BeginInvoke(new MethodInvoker(delegate { this.Close(); }));
}
0 голосов
/ 24 июля 2013

Другой обходной путь может быть, если вы установите верхний уровень в false, а затем вернете его в значение true. Странно, но это работает. Таким образом, код может быть следующим для отображения формы с нисходящей способностью в простом фоновом потоке:

for (int i = 0; i < 50; i++)
{
     ppaForm.SetBitmap(bitmap, (byte)(255 - i * 5));
     ppaForm.Show();
     ppaForm.TopMost = false;
     ppaForm.TopMost = true;

     Thread.Sleep(6);
}

В этом случае ppaForm - это PerPixelAlphaForm, описание которого вы можете найти здесь .

...