2016-09-21 2 views
1

Я создаю приложение, в котором он запускает форму FormSelect(), предлагая пользователю выбрать элемент в списке, когда пользователь нажимает кнопку «Выбрать», он создаст новый экземпляр MainForm (), скрыть FormSelect и показать MainForm, но он не работает, я получаю исключение со всеми тестами, которые я сделал.Form Show не работает с потоками

Вот некоторые коды:

static class Program { 
     public static MainForm mainForm; 
     /// <summary> 
     /// The main entry point for the application. 
     /// </summary> 
     [STAThread] 
     static void Main() { 
      Application.EnableVisualStyles(); 
      Application.SetCompatibleTextRenderingDefault(false); 
      Application.Run(new FormSelect()); 
     } 
    } 

Ничего особенного в моем FormSelect, так вот кнопка мыши, где она начала MainForm:

private async void btnSelect_Click(object sender, EventArgs e) { 

      loadingSpiner.Visible = true; 
      btnSelect.Enabled = false; 

      int index = listProcess.SelectedIndex; 

      await startMainForm(index); 

      this.Hide(); 
      Program.mainForm.Show(); 
     } 

private async Task startMainForm(int index) { 

      await Task.Run(() => { 
       Program.mainForm = new MainForm(runningProcess[index]); 
      }); 
     } 

Как вы можете видеть выше, я используя Task для запуска MainForm, чтобы он не замораживал мой пользовательский интерфейс и мой «загрузочный лоток»

Но когда он пытается использовать .Show(), я получаю исключение перекрестной резьбы, поэтому я попытался вызвать этот actio п с помощью:

this.Invoke(new MethodInvoker(delegate() { Program.mainForm.Show(); })); 

Но с помощью метода выше, я получаю исключение, говоря:

исключение типа «System.ComponentModel.Win32Exception» произошло в System.Windows.Forms.dll, но не обрабатывается код пользователя

Дополнительная информация: Ошибка при создании дескриптора окна.

Если я удалю «Ожидание Task.Run() ...» в методе startMainForm, все работает нормально, но полностью блокирует интерфейс FormSelect.

Как я могу избежать этой проблемы? Спасибо!

+1

вы не должны открывать какие-либо ui с uithread. –

+4

Вы не можете создавать пользовательский интерфейс в любом потоке, отличном от потока, используемого для вызова 'Application.Run' - чаще всего называемого потоком пользовательского интерфейса. – Enigmativity

+0

Я думаю, что форма «по умолчанию», которая запускается при запуске приложения, указана в Program.cs. В Program.cs вы должны найти вызов для запуска этой формы, которая должна блокироваться (поскольку в этот момент мы однопоточно), и после этого добавьте код, чтобы начать следующую форму? – XtrmJosh

ответ

1

Вы не можете сделать это таким образом.

Без хорошего Minimal, Complete, and Verifiable code example, который надежно воспроизводит проблему, невозможно точно сказать, какое лучшее решение для вашего сценария. Но объекты UI должны создаваться и использоваться только в потоке пользовательского интерфейса. Вы не можете создать свой экземпляр MainForm в рабочем потоке.

Поскольку ваш пример кода неполный, непонятно, почему вы пытаетесь создать экземпляр MainForm, используя, в первую очередь, Task.Run(). Весь этот код вызывает вызов конструктора, и конструкторы не должны занимать много времени.

Если у вас есть требующая много времени инициализация, вы должны абстрагироваться от этого класса MainForm, помещая его в какой-либо другой класс, который может быть передан в MainForm после его полной инициализации. Затем вы можете инициализировать этот другой класс, например. вызов Task.Run() (но все же не в конструкторе & hellip; создайте объект, а затем, если вам нужно асинхронно вызвать метод, который его инициализирует, сделайте это).

т.д .:

private async void btnSelect_Click(object sender, EventArgs e) { 
    loadingSpiner.Visible = true; 
    btnSelect.Enabled = false; 

    int index = listProcess.SelectedIndex; 

    MainFormData data = await startMainForm(index); 

    Program.mainForm = new MainForm(data); 
    this.Hide(); 
    Program.mainForm.Show(); 
} 

private async Task<MainFormData> startMainForm(int index) { 
    await Task.Run(() => { 
     MainFormData data = new MainFormData(); 
     data.Initialize(runningProcess[index]); 
     return data; 
    }); 
} 

class MainFormData 
{ 
    public MainFormData() { ... } 

    // You don't say what "runningProcess[index]" is, so placeholder here... 
    public void Initialize(object o) { ... } 
} 

Что-то в этом роде. Настройте, чтобы удовлетворить ваши потребности, конечно.

Конечно, этот класс должен инициализировать только аспекты, не связанные с UI. То есть данные, лежащие в основе вашего пользовательского интерфейса. Поскольку объекты пользовательского интерфейса, как правило, не требуют много времени для создания, я предполагаю, что это возможно в вашем случае.Если вы считаете, что инициализация самого пользовательского интерфейса требует много времени, то вам следует обратиться за помощью к выяснению, что это такое и как решить эту проблему. Конечно, опять же без хорошего MCVE здесь я ничего не могу прокомментировать конкретно по этому поводу.

+0

Спасибо, я переместил всю логику внутри конструктора MainForm (помимо InitializeComponent()) в задачу, возвращающую «MainFormData», поэтому я просто создал новую MainForm (FormData), и она работала хорошо. еще раз спасибо – Kyore

Смежные вопросы