Реализуйте загрузчик в форме Windows, как веб-приложение - PullRequest
2 голосов
/ 20 июня 2019

Я пытаюсь отобразить Loader во время выполнения любого длительного процесса в windows forms.Я реализовал код для этого, но загрузчик отображается, но не в CenterParent месте, он будет отображаться в центре экрана.

Код:

CPLoader - это форма, которую я хочу отобразить при выполнении любого процесса.

public class CommonLoader
{
    CPLoader cploader = new CPLoader();
    readonly Form form = null;

    public CommonLoader(Form frm)
    {
        form = frm;
    }

    public void ShowLoader()
    {
        try
        {
            if (form.InvokeRequired)
            {
                try
                {
                    cploader = new CPLoader();
                    cploader.ShowDialog();
                }
                catch 
                {
                    Console.WriteLine("Cp loader exception");
                }
            }
            else
            {
                Thread th = new Thread(ShowLoader);
                th.IsBackground = false;
                th.Start();
            }
        }
        catch
        {
            Console.WriteLine("Cp loader exception");
        }
    }

    /// <summary>
    /// this method will used for hide loader while process stop
    /// </summary>
    public void HideLoader()
    {
        try
        {
            if (cploader != null)
            {
                Thread.Sleep(200);
                cploader.Invoke(new Action(cploader.Close));
            }
        }
        catch
        {
            Console.WriteLine("Cp loader exception");
        }
    }
}

Я также попытался cploader.ShowDialog() с frm.BeginInvoke(new MethodInvoker(delegate(){cploader.ShowDialog(form); })).

Если я использую BeginInvoke(), тогда я 'Я не могу закрыть загрузчик.

1 Ответ

1 голос
/ 20 июня 2019

Заставки, экраны прогресса и т. Д. Появились в настольных приложениях 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> и использовать его для подачи сигнала про

...