#c_sharp #winforms #многопоточность
Дано: 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(); }
Ответы
Ответ 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, или использовать таски и проверять при нажатии кнопки что таска завершилась).Ответ 2
Не блокируйте поток UI долгими операциями. Выполняйте их асинхронно. Поэтому не стоит делать вещи вроде Thread.Sleep(). Не в коем случае не стоит в потоке UI вызывать вызывать методы (допустим SomeMethod(…)) возвращающие Task, просто SomeMethod(…).Result – это вызывает deadlock. Допустим есть метод возвращающий JSON: public static async Task 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 ; }
Комментариев нет:
Отправить комментарий