атрибут, как показано ниже.

сейчас у меня есть код C # для порождения нового окна в другом потоке, это работает, но как только открывается новое порожденное окно, оно закрывается и поток заканчивается. Как бы я сделал так, чтобы новое порожденное окно можно было закрыть с первого потока?

Вот «дерево» того, как в настоящее время работает нерест:

Основная тема
- Использует функцию в главном потоке для запуска другой функции в отдельном потоке, чтобы открыть окно w, в результате чего окно использует этот поток.

По сути, я просто хочу, чтобы у каждого окна была своя нить. И иметь возможность управлять порожденным вторичным окном из первого потока окна.

Ответы на вопрос(6)

Могу поспорить, что вы делаете что-то вроде этого:

new Thread(() => new TestForm().Show()).Start();

потому что это заставляет окно исчезнуть немедленно, как вы описываете.

Попробуйте это вместо этого:

 new Thread(() => new TestForm().ShowDialog()).Start();

ShowDialog раскручивает свой собственный насос сообщений и возвращается только тогда, когда окно закрыто.

 dahvyd04 апр. 2013 г., 06:22
Хорошее решение. Это также решило мою проблему, когда я получал исключение после вызоваApplication.Run(form); на новом потоке, что привело к невозможности закрытия формы основного потока.

создания окна?

Не видя код, я бы предположил, что проблема в том, что ваш второй поток не качает сообщения в очереди сообщений Windows.

Ты звонишьApplication.Run на вашей второй теме?

Кстати: обратите внимание, что у вашего дизайна есть некоторые ограничения. Первый поток не сможетнепосредственно контролировать второе окно. Всякий раз, когда вы пытаетесь манипулировать любым элементом пользовательского интерфейса во втором окне из первого потока, вам придется использоватьControl.Invoke чтобы убедиться, что фактические манипуляции с пользовательским интерфейсом происходят в правильном потоке.

Решение Вопроса

чем первый, который я написал. Это устраняет существующее состояние гонки с помощью p / invoke.

обновленный Все еще было состояние гонки. Вот этотдолжно быть идеальный.

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);
    }
}

Вот первый пример для потомков:

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";
    }
}
 chrispepper198912 нояб. 2015 г., 17:47
Будет ли закрытие формы очищать нить и форму правильно? Я пытался поместить мою вторую форму в «использование», но это привело к сбою приложения, потому что dispose был вызван из другого потока
 Tergiver13 нояб. 2015 г., 01:02
@ chrispepper1989 Похоже, что вы используете не вApplicationRunProc который выполняется в потоке, который создает форму и ее элементы управления. Возможно, вы могли бы задать это как новый вопрос и ссылку на него здесь. Таким образом, мы можем увидеть код. Создайте простой пример, подобный приведенному выше, который дублирует поведение, которое вы видите.
 Shn_Android_Dev26 апр. 2018 г., 03:01
Должен быть более простой способ открыть форму из потока, чем этот ...

В Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Threading;

namespace TwoWindows
{
    static class Program
    {
        public static Form1 form1;
        public static Form2 form2;
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false); 

            form1 = new Form1();
            form2 = new Form2();

            form1.Form2Property = form2;
            form2.Form1Property = form1;

            form1.Show();
            form2.Show();

            Application.Run();
        }
    }
}

В Form1.cs:

namespace TwoWindows
{
    public partial class Form1 : Form
    {
        public Form2 Form2Property { get; set; }

        public Form1()
        {
            InitializeComponent();
        }

        protected override void OnClosed(EventArgs e)
        {
            if (Form2Property.IsDisposed)
                Application.Exit();
        }
    }
}

И Form2.cs:

namespace TwoWindows
{
    public partial class Form2 : Form
    {
        public Form1 Form1Property { get; set; }

        public Form2()
        {
            InitializeComponent();
        }

        protected override void OnClosed(EventArgs e)
        {
            if (Form1Property.IsDisposed)
                Application.Exit();
        }
    }
}

Таким образом, вы можете получить две формы в одном потоке и использовать одну для управления другой. Если вам нужно использовать потоки, я бы предложил использовать выделенные потоки, которые являются частью классов, а не порождать в методе, который можно вызывать более одного раза. Затем используйте ManualResetEvent или AutoResetEvent для управления обработкой потока. Мне действительно нравится подход использования чего-то подобного, потому что это безопасно и не тратит много ресурсов на инициализацию потоков.

public class MyClassOrForm
{
    Thread myProcessingThread;
    public AutoResetEvent startProcessing = new AutoResetEvent(false);
    public AutoResetEvent processingFinished = new AutoResetEvent(false);
    public AutoResetEvent killProcessingThread = new AutoResetEvent(false);

    public MyClassOrForm()
    {
        myProcessingThread = new Thread(MyProcess);
    }

    private void MyProcess()
    {
        while (true)
        {
            if (startProcessing.WaitOne())
            {
                // Do processing here

                processingFinished.Set();
            }

            if (killProcessingThread.WaitOne(0))
                return;
        }
    }
}

Затем, как только вы установили данные для обработки, вызовите другой класс или метод

MyClassOrMethodInstance.startProcessing.Set();

И если вам нужно дождаться окончания обработки, вставьте:

MyClassOrMethodInstance.processingFinished.WaitOne(time_out_ms);

Это эквивалентно вызову Thread.Join (), только то, что вам не нужно каждый раз выделять другой поток с рисками, связанными с потоками, если они зависят от локальных данных или незавершенных дочерних потоков.

которое является многопоточным и использует пользовательский интерфейс в созданном потоке для отправки функциональности рисования в DC.

Когда мы портировали приложение для запуска из командной строки, у нас, естественно, возникла небольшая проблема, поскольку поток диспетчера не был создан или не нужен - поэтому я создал другой поток из точки входа приложения, который по сути называется ShowDialog () (единственный способ раскручивать насос сообщений) на главной форме - с помощью переопределенного OnShown, чтобы навсегда скрыть и минимизировать форму при совершении вызова. Это позволило мне по-прежнему отправлять в форму и обрабатывать все мои рисунки из других нескольких потоков.

Это, конечно, уродливый подход, но это был быстрый способ сделать это, и он работает, как и ожидалось.

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

Он содержит один ProgressBar со следующими настройками:

progressBar1.Style=ProgressBarStyles.MarqueeprogressBar1.MarqueeAnimationSpeed = <- установите свою скорость в миллисекундах здесь

Если вы хотите, вы можете установить формуTopMost собственность наtrue.

Вот код для формы:

public partial class BusyForm : Form
{
    public BusyForm(string text = "Busy performing action ...")
    {
        InitializeComponent();
        this.Text = text;
        this.ControlBox = false;
    }

    public void Start()
    {
        System.Threading.Tasks.Task.Run(() =>
        {
            this.ShowDialog();
        });
    }

    public void Stop()
    {
        BeginInvoke((Action)delegate { this.Close(); });
    }

    public void ChangeText(string newText)
    {
        BeginInvoke((Action)delegate { this.Text = newText; });
    }
}

А вот код для использования формы в вашем коде:

        BusyForm busyForm = new BusyForm(text: "Opening database ...");

        busyForm.Start();

        //do your stuff here

        busyForm.Stop();

ОБНОВИТЬ: Я столкнулся с некоторыми основными проблемами с потоками. Вот обновленная версия кода. Для некоторой справочной информации эта форма имеет индикатор выполнения, который отображается, когда задача занята. Я добавилChangeText Команда, чтобы показать пример того, как вы можете взаимодействовать с этой формой из другой формы. Следует также упомянуть, что вашMain вProgram.cs должен иметь[STAThread] атрибут, как показано ниже.

    [STAThread]
    static void Main(string[] args)
    {
        System.Globalization.CultureInfo.DefaultThreadCurrentCulture = System.Globalization.CultureInfo.InvariantCulture;
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }

Ваш ответ на вопрос