1

我有一个作为表单的主线程,它启动另一个应用程序,在本例中为记事本,然后我生成一个等待记事本关闭的 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();
    }
}

还有其他想法吗?或者有人可以修复我上面的代码吗?我已经处理这个问题好几个星期了,而且很慌张。

谢谢!

4

2 回答 2

1

DoWork调用过程后在 BackgroundWorker 的方法中所做的任何工作都RunWorkerAsync不会在 UI 线程上运行,但您的代码正在后台创建表单。

表单是 UI 元素,所以这不起作用:

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方法,因为您试图在没有ShowDialog调用的情况下使 Form2 保持活动状态,因此请尝试订阅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(); }));
}
于 2012-03-27T21:12:33.330 回答
0

另一种解决方法是,如果您将 topmost 设置为 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,您可以在此处找到描述。

于 2013-07-24T18:48:59.500 回答