Заставки, экраны прогресса и т. Д. Появились в настольных приложениях Visual Basic или Delphi задолго до веб-приложений. Это просто немодальные формы / окна, отображаемые поверх их приложения. Им также не нужны потоки - тогда приложения были в основном однопоточными.
Фоновые потоки не могут изменить пользовательский интерфейс в любом случае, что означает, что весь метод ShowLoader
делает только попытку вызова:
cploader = new CPLoader();
cploader.ShowDialog();
Все это можно заменить на
public void ShowLoader()
{
cploader.ShowDialog();
}
public void HideLoader()
{
cploader.Hide();
//or Close if we don't intend to reuse the loader
}
Указание родителя
Вызов ShowDialog без каких-либо параметров создает окно, чьим родителем является рабочий стол. Вот почему окно отображается по центру экрана, а не приложения.
Чтобы указать владельца / родителя, просто передайте его как owner
параметр ShowDialog или Show .
Следующий код может использоваться для отображения диалогового окна с центром в текущей форме:
var myDialog=new MyDialogForm();
myDialog.ShowDialog(this);
Это означает, что ShowLoader
, вероятно, должен принять владельца в качестве параметра:
public void ShowLoader(Form frm)
{
cploader.ShowDialog(frm);
}
немодальные окна
ShowDialog()
используется для отображения модальной формы - формы, которая сохраняет фокус, пока не будет закрыта, как диалоговое окно. Вот почему метод называется ShowDialog()
вместо ShowModal()
.
Загрузчик должен быть немодальным, поэтому вместо него следует использовать Show
:
public void ShowLoader(Form frm)
{
cploader.Show(frm);
}
Другое отличие состоит в том, что ShowDialog
возвращает результат с выбором пользователя (ОК, Отмена и т. Д.), А Show
ничего не возвращает.
Модальный загрузчик с уведомлением
Если вы хотите создать модальный загрузчик с ShowDialog
, но по-прежнему выполнять некоторую работу в фоновом режиме, вам нужен способ уведомить этого загрузчика из фонового потока. Это можно сделать с помощью класса Progress .
Загрузчик может выставить IProgress<T>
как свойство. Параметр T
может быть простой строкой или целым числом, показывающим прогресс, или сложной сущностью с прогрессом, строковым сообщением и индикатором состояния. Ради лени, давайте использовать string
и закроем диалоговое окно, если значение пустое:
public IProgress<string> Progress{get;private set;}
public CPLoader()
{
this.Progress=new Progress<string>(UpdateUI);
}
private void UpdateUI(string msg)
{
if(String.IsNullOrWhitespace(msg))
{
this.DialogResult=DialogResult.Cancel;
this.Close();
}
else
{
this.SomeLabel.Text=msg;
}
}
Код, который работает в фоновом режиме, нуждается в доступе к этому свойству IProgress<string>
. Скажем, код, который должен работать в фоновом режиме:
void Work(IProgress<string> progress)
{
for(int i=0;i<1000000;i++)
{
//Do something CPU intensive
//Report every 1000 items
if(i%1000==0)
{
progress.Report($"{i} out of 1000000");
}
}
//This tells the loader to close.
progress.Report("");
}
Этот код может работать в фоновом режиме и использовать загрузчик следующим образом:
var loader=new CPLoader();
var task=Task.Run(()=>DoWork(loader.Progress));
loader.ShowDialog();
await task;
Загрузчик инициализируется первым, давая нам доступ к экземпляру IProgress<T>
. После этого задание запускается в фоновом режиме с Task.Run
. Когда он заканчивается, он отправляет пустую строку прогресса и метод загрузчика UpdateUI
закрывает диалоговое окно в ответ
Код, который должен выполнять работу при загрузке, может получить доступ к этому интерфейсу IProgress<string>
и использовать его для подачи сигнала про