由EventHandler创建的C#Windows窗体立即消失

时间:2021-06-22 15:51:53

I don't know why this is happening, but when I create a new form inside an EventHandler, it disappears as soon as the method is finished.

我不知道为什么会这样,但是当我在EventHandler中创建一个新表单时,它会在方法完成后立即消失。

Here's my code. I've edited it for clarity, but logically, it is exactly the same.

这是我的代码。为了清晰起见,我编辑了它,但从逻辑上讲,它完全相同。

static void Main()
{
    myEventHandler = new EventHandler(launchForm);
    // Code that creates a thread which calls
    // someThreadedFunction() when finished.
}

private void someThreadedFunction()
{
    //Do stuff

    //Launch eventhandler
    EventHandler handler = myEventHandler;
    if (handler != null)
    {
        handler(null, null);
        myEventHandler = null;
    }
}

private void launchForm(object sender, EventArgs e)
{
    mf = new myForm();
    mf.Show();
    MessageBox.Show("Do you see the form?");
}

private myForm mf;
private EventHandler myEventHandler;

The new form displays as long as the MessageBox "Do you see the form?" is there. As soon as I click OK on it, the form disappears.

只要MessageBox“你看到表单了吗?”就会显示新表单。在那儿。只要我单击“确定”,表单就会消失。

What am I missing? I thought that by assigning the new form to a class variable, it would stay alive after the method finished. Apparently, this is not the case.

我错过了什么?我认为通过将新表单分配给类变量,它将在方法完成后保持活动状态。显然,事实并非如此。

5 个解决方案

#1


I believe the problem is that you are executing the code within the handler from your custom thread, and not the UI thread, which is required because it operates the Windows message pump. You want to use the Invoke method here to insure that the form gets and shown on the UI thread.

我认为问题在于您是从自定义线程执行处理程序中的代码,而不是UI线程,这是必需的,因为它操作Windows消息泵。您希望在此处使用Invoke方法来确保表单获取并显示在UI线程上。

private void launchForm(object sender, EventArgs e)
{
    formThatAlreadyExists.Invoke(new MethodInvoker(() =>
    {
        mf = new myForm();
        mf.Show();
        MessageBox.Show("Do you see the form?");
    }));
}

Note that this assumes you already have a WinForms object (called formThatAlreadyExists) that you have run using Application.Run. Also, there may be a better place to put the Invoke call in your code, but this is at least an example of it can be used.

请注意,这假设您已经使用Application.Run运行了WinForms对象(称为formThatAlreadyExists)。此外,可能有一个更好的地方将Invoke调用放在您的代码中,但这至少是一个可以使用的示例。

#2


I think if you create a form on a thread, the form is owned by that thread. When creating any UI elements, it should always be done on the main (UI) thread.

我想如果你在一个线程上创建一个表单,那么该表单就是该线程所拥有的。在创建任何UI元素时,应始终在主(UI)线程上完成。

#3


this looks as if you are not on the form sta thread so once you show the form it is gone and the thread finishes it's job it kills it self since there is nothing referenceing the thread. Its not the best solution out there for this but you ca use a showdialog() rather than a show to accomplish it keeping state if you need a code example i use this exact same process for a "loading...." form

这看起来好像你不在表单sta线程上,所以一旦你显示表单它就消失了,并且线程完成它的工作它会自动杀死它,因为没有任何引用线程。它不是最好的解决方案,但你可以使用showdialog()而不是一个节目来完成它保持状态,如果你需要一个代码示例我使用这个完全相同的过程“loading ....”形式

public class Loading
{
    public delegate void EmptyDelegate();
    private frmLoadingForm _frmLoadingForm;
    private readonly Thread _newthread;
    public Loading()
    {
        Console.WriteLine("enteredFrmLoading on thread: " + Thread.CurrentThread.ManagedThreadId);
        _newthread = new Thread(new ThreadStart(Load));
        _newthread.SetApartmentState(ApartmentState.STA);
        _newthread.Start();
    }

    public void Load()
    {
        Console.WriteLine("enteredFrmLoading.Load on thread: " + Thread.CurrentThread.ManagedThreadId);
        _frmLoadingForm = new frmLoadingForm();
        if(_frmLoadingForm.ShowDialog()==DialogResult.OK)
        {

        }
    }


    /// <summary>
    /// Closes this instance.
    /// </summary>
    public void Close()
    {
        Console.WriteLine("enteredFrmLoading.Close on thread: " + Thread.CurrentThread.ManagedThreadId);
        if (_frmLoadingForm != null)
        {
            if (_frmLoadingForm.InvokeRequired)
            {
                _frmLoadingForm.Invoke(new EmptyDelegate(_frmLoadingForm.Close));
            }
            else
            {
                _frmLoadingForm.Close();
            }
        }
        _newthread.Abort();
    }
}
public partial class frmLoadingForm : Form
{

    public frmLoadingForm()
    {
        InitializeComponent();
    }
}

#4


Is

dbf.Show();

a typo? Is it supposed to be this instead?

一个错字?它应该是这样吗?

mf.Show(); 

Is it possible that there is another form that you are showing other than the one you intend to show?

是否有可能除了您打算展示的表格之外还有其他表格?

#5


You created a window on a non UI thread. When the thread aborts it will take your window along with it. End of story. Perform invoke on the main form passing a delegate which will execute the method that creates the messagebox on the UI thread. Since the MessageBox is a modal window, if dont want the launchForm method to block the background thread, create a custom form with the required UI and call show() on it, not ShowDialog().

您在非UI线程上创建了一个窗口。当线程中止时,它将带你的窗口。故事结局。在主窗体上执行调用,传递委托,该委托将执行在UI线程上创建消息框的方法。由于MessageBox是一个模态窗口,如果不希望launchForm方法阻止后台线程,请创建一个带有所需UI的自定义表单并在其上调用show(),而不是ShowDialog()。

#1


I believe the problem is that you are executing the code within the handler from your custom thread, and not the UI thread, which is required because it operates the Windows message pump. You want to use the Invoke method here to insure that the form gets and shown on the UI thread.

我认为问题在于您是从自定义线程执行处理程序中的代码,而不是UI线程,这是必需的,因为它操作Windows消息泵。您希望在此处使用Invoke方法来确保表单获取并显示在UI线程上。

private void launchForm(object sender, EventArgs e)
{
    formThatAlreadyExists.Invoke(new MethodInvoker(() =>
    {
        mf = new myForm();
        mf.Show();
        MessageBox.Show("Do you see the form?");
    }));
}

Note that this assumes you already have a WinForms object (called formThatAlreadyExists) that you have run using Application.Run. Also, there may be a better place to put the Invoke call in your code, but this is at least an example of it can be used.

请注意,这假设您已经使用Application.Run运行了WinForms对象(称为formThatAlreadyExists)。此外,可能有一个更好的地方将Invoke调用放在您的代码中,但这至少是一个可以使用的示例。

#2


I think if you create a form on a thread, the form is owned by that thread. When creating any UI elements, it should always be done on the main (UI) thread.

我想如果你在一个线程上创建一个表单,那么该表单就是该线程所拥有的。在创建任何UI元素时,应始终在主(UI)线程上完成。

#3


this looks as if you are not on the form sta thread so once you show the form it is gone and the thread finishes it's job it kills it self since there is nothing referenceing the thread. Its not the best solution out there for this but you ca use a showdialog() rather than a show to accomplish it keeping state if you need a code example i use this exact same process for a "loading...." form

这看起来好像你不在表单sta线程上,所以一旦你显示表单它就消失了,并且线程完成它的工作它会自动杀死它,因为没有任何引用线程。它不是最好的解决方案,但你可以使用showdialog()而不是一个节目来完成它保持状态,如果你需要一个代码示例我使用这个完全相同的过程“loading ....”形式

public class Loading
{
    public delegate void EmptyDelegate();
    private frmLoadingForm _frmLoadingForm;
    private readonly Thread _newthread;
    public Loading()
    {
        Console.WriteLine("enteredFrmLoading on thread: " + Thread.CurrentThread.ManagedThreadId);
        _newthread = new Thread(new ThreadStart(Load));
        _newthread.SetApartmentState(ApartmentState.STA);
        _newthread.Start();
    }

    public void Load()
    {
        Console.WriteLine("enteredFrmLoading.Load on thread: " + Thread.CurrentThread.ManagedThreadId);
        _frmLoadingForm = new frmLoadingForm();
        if(_frmLoadingForm.ShowDialog()==DialogResult.OK)
        {

        }
    }


    /// <summary>
    /// Closes this instance.
    /// </summary>
    public void Close()
    {
        Console.WriteLine("enteredFrmLoading.Close on thread: " + Thread.CurrentThread.ManagedThreadId);
        if (_frmLoadingForm != null)
        {
            if (_frmLoadingForm.InvokeRequired)
            {
                _frmLoadingForm.Invoke(new EmptyDelegate(_frmLoadingForm.Close));
            }
            else
            {
                _frmLoadingForm.Close();
            }
        }
        _newthread.Abort();
    }
}
public partial class frmLoadingForm : Form
{

    public frmLoadingForm()
    {
        InitializeComponent();
    }
}

#4


Is

dbf.Show();

a typo? Is it supposed to be this instead?

一个错字?它应该是这样吗?

mf.Show(); 

Is it possible that there is another form that you are showing other than the one you intend to show?

是否有可能除了您打算展示的表格之外还有其他表格?

#5


You created a window on a non UI thread. When the thread aborts it will take your window along with it. End of story. Perform invoke on the main form passing a delegate which will execute the method that creates the messagebox on the UI thread. Since the MessageBox is a modal window, if dont want the launchForm method to block the background thread, create a custom form with the required UI and call show() on it, not ShowDialog().

您在非UI线程上创建了一个窗口。当线程中止时,它将带你的窗口。故事结局。在主窗体上执行调用,传递委托,该委托将执行在UI线程上创建消息框的方法。由于MessageBox是一个模态窗口,如果不希望launchForm方法阻止后台线程,请创建一个带有所需UI的自定义表单并在其上调用show(),而不是ShowDialog()。