Открывать вторую winform асинхронно, но все же вести себя как ребенок в родительской форме?
Я создаю приложение, и я хотел бы реализовать окно прогресса, которое появляется, когда происходит длительный процесс.
Я создал стандартный проект формы Windows, к которому я создал свое приложение, используя форму по умолчанию. Я также создал новую форму для использования в качестве окна прогресса.
Проблема возникает, когда я открываю окно выполнения (в функции), используя:
ProgressWindow.ShowDialog();
Когда эта команда встречается, фокус находится в окне выполнения, и я предполагаю, что теперь это окно, которое mainloop обрабатывается для событий. Недостатком является то, что он блокирует выполнение моей длительной операции в основной форме.
Если я открою окно выполнения, используя:
ProgressWindow.Show();
Затем окно открывается правильно и теперь не блокирует выполнение основной формы, но оно не действует как дочернее (модальное) окно, то есть позволяет выбрать основную форму, не центрируется на родительском, и т.д.
Любые идеи, как я могу открыть новое окно, но продолжить обработку в основной форме?
Ответы
Ответ 1
Вероятно, вы начинаете свою длительную операцию в отдельном рабочем потоке (например, используя фонового работника). Затем покажите свою форму с помощью ShowDialog()
и по завершении потока закройте диалоговое окно, которое вы показываете.
Вот пример - в этом я предполагаю, что у вас две формы (Form1
и Form2
). На Form1
я вытащил BackgroundWorker
из панели инструментов. Затем я связал событие RunWorkerComplete
BackgroundWorker
с обработчиком событий в моей форме. Вот код, который обрабатывает события и показывает диалог:
public partial class Form1 : Form
{
public Form1() {
InitializeComponent();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) {
Thread.Sleep(5000);
e.Result = e.Argument;
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
var dlg = e.Result as Form2;
if (dlg != null) {
dlg.Close();
}
}
private void button1_Click(object sender, EventArgs e) {
var dlg = new Form2();
this.backgroundWorker1.RunWorkerAsync(dlg);
dlg.ShowDialog();
}
}
Ответ 2
Другая опция:
Используйте ProgressWindow.Show()
и сами реализуйте поведение модального окна. parentForm.Enabled = false
, расположите форму самостоятельно и т.д.
Ответ 3
Я реализовал что-то очень похожее на это для другого проекта. Эта форма позволяет вам отображать модальный диалог внутри рабочего потока:
public partial class NotificationForm : Form
{
public static SynchronizationContext SyncContext { get; set; }
public string Message
{
get { return lblNotification.Text; }
set { lblNotification.Text = value; }
}
public bool CloseOnClick { get; set; }
public NotificationForm()
{
InitializeComponent();
}
public static NotificationForm AsyncShowDialog(string message, bool closeOnClick)
{
if (SyncContext == null)
throw new ArgumentNullException("SyncContext",
"NotificationForm requires a SyncContext in order to execute AsyncShowDialog");
NotificationForm form = null;
//Create the form synchronously on the SyncContext thread
SyncContext.Send(s => form = CreateForm(message, closeOnClick), null);
//Call ShowDialog on the SyncContext thread and return immediately to calling thread
SyncContext.Post(s => form.ShowDialog(), null);
return form;
}
public static void ShowDialog(string message)
{
//Perform a blocking ShowDialog call in the calling thread
var form = CreateForm(message, true);
form.ShowDialog();
}
private static NotificationForm CreateForm(string message, bool closeOnClick)
{
NotificationForm form = new NotificationForm();
form.Message = message;
form.CloseOnClick = closeOnClick;
return form;
}
public void AsyncClose()
{
SyncContext.Post(s => Close(), null);
}
private void NotificationForm_Load(object sender, EventArgs e)
{
}
private void lblNotification_Click(object sender, EventArgs e)
{
if (CloseOnClick)
Close();
}
}
Чтобы использовать, вам нужно установить SyncContext где-то в вашем потоке графического интерфейса:
NotificationForm.SyncContext = SynchronizationContext.Current;