代码之家  ›  专栏  ›  技术社区  ›  Andrew Ensley

由事件处理程序创建的C#Windows窗体立即消失

  •  1
  • Andrew Ensley  · 技术社区  · 17 年前

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

    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;
    

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

    5 回复  |  直到 17 年前
        1
  •  5
  •   Noldorin    17 年前

    我认为问题在于,您正在从自定义线程执行处理程序中的代码,并且 不 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?");
        }));
    }
    

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

        2
  •  1
  •   TheSean    17 年前

    我认为,如果你在一个线程上创建一个表单,那么该表单就归该线程所有。创建任何UI元素时,都应该在主(UI)线程上完成。

        3
  •  1
  •   Brandon Grossutti    17 年前

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

    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
  •  0
  •   Andrew Hare    17 年前

    是

    dbf.Show();
    

    拼写错误?应该是这个吗?

    mf.Show(); 
    

    除了你打算展示的形式,你是否有可能展示另一种形式?

        5
  •  0
  •   bobbyalex    17 年前

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

    推荐文章