Как загрузить вторую форму асинхронно и запустить её при нажатии кнопки пользователем?

300
10 июня 2017, 12:48

Дано: 2 формы.

Главная форма содержит кнопку по которой вызывается второстепенная форма (форма 2).

Форма 2 содержит паузу System.Threading.Thread.Sleep(10000) для имитации сложной работы (загрузки компонентов, множества изображений, отрисовки).

Задача: мгновенно отобразить форму 2 при нажатии кнопки на главной форме. При этом до нажатия кнопки, пользователь не должен видеть форму 2 (даже мелькающую). Кнопку пользователь нажмет не ранее, чем через 10 секунд после старта программы.

Я перепробовал варианты с запуском в другом потоке, пытался использовать просто Task, BackgroundWorker, ThreadPool. Не получается, как правило проблема при вызове формы по второй кнопке.

Какие есть идея?

Один из примеров, как я пытался решить задачу:

private void Form1_Load(object sender, EventArgs e)
{
        BackgroundWorker bw = new BackgroundWorker();
        bw.DoWork += (s, ea) =>
        {
            frm.Show();
            // В форме 2 стоит this.Visible = false;
        };
        bw.RunWorkerAsync();
}
private void button1_Click(object sender, EventArgs e)
{
        Console.WriteLine("button1_Click");
        this.Invoke(new MethodInvoker(frm.ShowForm));
}
// Form 2:
public void ShowForm()
{
        Console.WriteLine("Form2 showForm");
        this.Visible = true;
        this.WindowState = FormWindowState.Normal;
        this.BringToFront();
}
Answer 1

Всю долгую логику надо засунуть в конструктор второй формы (это я думаю логично). А дальше при запуске первой, в отдельном потоке создать вторую форму. И оставить её в памяти. По клику по кнопке её просто показать. Что то вот в этом роде:

   public partial class Form1 : Form
    {
        private Form2 _form;
        public Form1()
        {
            InitializeComponent();
            new Thread(()=>{_form = new Form2();}).Start();
        }
        private void button1_Click(object sender, EventArgs e)
        {
            _form.Show();
        }
    }

Единственная проблема данного кода, если пользователь нажмет кнопку ДО того как форма загрузится, все упадет. Но тут можно или просто проверять на Null, или использовать таски и проверять при нажатии кнопки что таска завершилась).

Answer 2
Не блокируйте поток UI долгими операциями. Выполняйте их асинхронно.

Поэтому не стоит делать вещи вроде Thread.Sleep(). Не в коем случае не стоит в потоке UI вызывать вызывать методы (допустим SomeMethod(…)) возвращающие Task<T>, просто SomeMethod(…).Result – это вызывает deadlock.

Допустим есть метод возвращающий JSON:

public static async Task<JObject> GetJsonAsync(Uri uri)
{
    using (var client = new HttpClient())
    {
        var jsonString = await client.GetStringAsync(uri);
        return JObject.Parse(jsonString);
    }
}

Вот так делать неправильно, мы так получим deadlock.

private void Button1_Click(...)
{
    var jsonTask = GetJsonAsync(...);
    // Тут мы получаем deadlock
    textBox1.Text = jsonTask.Result;
}

Вместо это правильно было бы сделать так:

public async void Button1_Click(...)
{
    var json = await GetJsonAsync(...);
    textBox1.Text = json;
}

Вывод

Решаем задачи освобождения потока UI таким образом: добавляем модификатор async к обработчику события (это Load, Click и т.д., в основном они получаются async void). Далее внутри него выполняем какой-либо Task с помощью await.

Поэтому в итоге что-то получается вроде:

private async void Form_Load(object sender, EventArgs e)
{
    await Task.Delay(10000); // Допустим сделаем ожидание 10 секунд
    var r = await  // Некоторый Task<Result>;
}
READ ALSO
Печать машинного представления float

Печать машинного представления float

Есть стандарт IEEE 754 двоичного представления чисел и их арифметикиВ нем описываются нормализованные числа и ненормализованные

235
Патч private на public

Патч private на public

Как пропатчить переменную в dll с private на public удаленно?

231
Работа с RDP/SSH в C# [требует правки]

Работа с RDP/SSH в C# [требует правки]

Возможно ли запустить программу командой через rdp или ssh зная ток имя файла, если да, то можно поподробнее?

226
Как вывести все данные из таблицы в Unity?

Как вывести все данные из таблицы в Unity?

Как вывести все подряд данные из таблицы в Unity? Есть такой код, но выдает ошибку:

364