Spawn a new thread to open a new window and close it from a different thread

后端 未结 6 1242
天涯浪人
天涯浪人 2020-12-01 03:57

Right now I have C# code to spawn a new window in a different thread, this works, but as soon as the new spawned window opens, it closes and the thread ends. How would I mak

6条回答
  •  不思量自难忘°
    2020-12-01 04:44

    This is just a quick example. It's a little more robust than the first one I wrote. It eliminates the existing race condition by using p/invoke.

    Updated Still had a race condition. This one should be perfect.

    using System;
    using System.Drawing;
    using System.Runtime.InteropServices;
    using System.Threading;
    using System.Windows.Forms;
    
    class MainUIThreadForm : Form
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MainUIThreadForm());
        }
    
        private IntPtr secondThreadFormHandle;
    
        public MainUIThreadForm()
        {
            Text = "First UI";
            Button button;
            Controls.Add(button = new Button { Name = "Start", Text = "Start second UI thread", AutoSize = true, Location = new Point(10, 10) });
            button.Click += (s, e) =>
            {
                if (secondThreadFormHandle == IntPtr.Zero)
                {
                    Form form = new Form
                    {
                        Text = "Second UI",
                        Location = new Point(Right, Top),
                        StartPosition = FormStartPosition.Manual,
                    };
                    form.HandleCreated += SecondFormHandleCreated;
                    form.HandleDestroyed += SecondFormHandleDestroyed;
                    form.RunInNewThread(false);
                }
            };
            Controls.Add(button = new Button { Name = "Stop", Text = "Stop second UI thread", AutoSize = true, Location = new Point(10, 40), Enabled = false });
            button.Click += (s, e) =>
            {
                if (secondThreadFormHandle != IntPtr.Zero)
                    PostMessage(secondThreadFormHandle, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
            };
        }
    
        void EnableStopButton(bool enabled)
        {
            if (InvokeRequired)
                BeginInvoke((Action)(() => EnableStopButton(enabled)));
            else
            {
                Control stopButton = Controls["Stop"];
                if (stopButton != null)
                    stopButton.Enabled = enabled;
            }
        }
    
        void SecondFormHandleCreated(object sender, EventArgs e)
        {
            Control second = sender as Control;
            secondThreadFormHandle = second.Handle;
            second.HandleCreated -= SecondFormHandleCreated;
            EnableStopButton(true);
        }
    
        void SecondFormHandleDestroyed(object sender, EventArgs e)
        {
            Control second = sender as Control;
            secondThreadFormHandle = IntPtr.Zero;
            second.HandleDestroyed -= SecondFormHandleDestroyed;
            EnableStopButton(false);
        }
    
        const int WM_CLOSE = 0x0010;
        [DllImport("User32.dll")]
        extern static IntPtr PostMessage(IntPtr hWnd, int message, IntPtr wParam, IntPtr lParam);
    }
    
    internal static class FormExtensions
    {
        private static void ApplicationRunProc(object state)
        {
            Application.Run(state as Form);
        }
    
        public static void RunInNewThread(this Form form, bool isBackground)
        {
            if (form == null)
                throw new ArgumentNullException("form");
            if (form.IsHandleCreated)
                throw new InvalidOperationException("Form is already running.");
            Thread thread = new Thread(ApplicationRunProc);
            thread.SetApartmentState(ApartmentState.STA);
            thread.IsBackground = isBackground;
            thread.Start(form);
        }
    }
    

    Here is the first example for posterity:

    using System;
    using System.Drawing;
    using System.Threading;
    using System.Windows.Forms;
    
    class MainUIThreadForm : Form
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MainUIThreadForm());
        }
    
        SecondUIThreadForm secondThreadForm;
        public MainUIThreadForm()
        {
            Text = "First UI";
            Button button;
            Controls.Add(button = new Button { Text = "Start second UI thread", AutoSize = true, Location = new Point(10, 10) });
            button.Click += (s, e) =>
                {
                    if (secondThreadForm == null || !secondThreadForm.IsHandleCreated)
                        secondThreadForm = SecondUIThreadForm.Create();
                };
            Controls.Add(button = new Button { Text = "Stop second UI thread", AutoSize = true, Location = new Point(10, 40) });
            button.Click += (s, e) =>
            {
                if (secondThreadForm != null && secondThreadForm.IsHandleCreated)
                    secondThreadForm.Invoke((Action)(() => secondThreadForm.Close()));
            };
        }
    }
    
    class SecondUIThreadForm : Form
    {
        static void Main2(object state)
        {
            Application.Run((Form)state);
        }
    
        public static SecondUIThreadForm Create()
        {
            SecondUIThreadForm form = new SecondUIThreadForm();
            Thread thread = new Thread(Main2);
            thread.SetApartmentState(ApartmentState.STA);
            thread.Start(form);
            return form;
        }
    
        public SecondUIThreadForm()
        {
            Text = "Second UI";
        }
    }
    

提交回复
热议问题