简体   繁体   English

像Web应用程序一样以windows形式实现加载器

[英]Implement loader in windows form like web application

I'm trying displaying Loader while any long running process being executing in windows forms .我正在尝试在windows forms中执行任何长时间运行的进程时显示Loader I have implemented code for that, but loader being displayed but not in CenterParent location, it will be displayed on Center of the screen.我已经为此实现了代码,但是加载器正在显示但不在CenterParent位置,它将显示在屏幕的中心。

Code:代码:

CPLoader is form that I want to display while any process executing. 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");
        }
    }
}

I have also try cploader.ShowDialog() with frm.BeginInvoke(new MethodInvoker(delegate(){cploader.ShowDialog(form); })) .我也尝试了cploader.ShowDialog()frm.BeginInvoke(new MethodInvoker(delegate(){cploader.ShowDialog(form); }))

If I use BeginInvoke() then I'm unable to close the loader.如果我使用BeginInvoke()则无法关闭加载程序。

Splash screens, progress screens etc appeared in Visual Basic or Delphi desktop applications long before web applications.闪屏、进度屏幕等早在 Web 应用程序之前就出现在 Visual Basic 或 Delphi 桌面应用程序中。 They are just modeless forms/windows displayed on top of their application.它们只是显示在其应用程序顶部的无模式表单/窗口。 They don't need threads either - back then applications were mostly single threaded.他们也不需要线程——当时的应用程序大多是单线程的。

Background threads can't modify the UI anyway, which means that the entire ShowLoader method does nothing more than try to call :后台线程无论如何都不能修改 UI,这意味着整个ShowLoader方法所做的只是尝试调用:

cploader = new CPLoader();
cploader.ShowDialog();

All of this can be replaced with所有这些都可以替换为

public void ShowLoader()
{
    cploader.ShowDialog();
}

public void HideLoader()
{
    cploader.Hide(); 
    //or Close if we don't intend to reuse the loader
}

Specifying the parent指定父级

Calling ShowDialog without any parameters creates a window whose parent is the desktop.不带任何参数调用ShowDialog会创建一个窗口,其父窗口是桌面。 That's why the window appears centered on the screen, not the application.这就是窗口显示在屏幕中央而不是应用程序的原因。

To specify an owner/parent, just pass it as the owner parameter to ShowDialog or Show .要指定所有者/父项,只需将其作为owner参数传递给ShowDialogShow

The following code can be used to display a dialog box centered on the current form :以下代码可用于显示以当前窗体为中心的对话框:

var myDialog=new MyDialogForm();
myDialog.ShowDialog(this);

This means that ShowLoader probably has to accept the owner as a parameter :这意味着ShowLoader可能必须接受所有者作为参数:

public void ShowLoader(Form frm)
{
    cploader.ShowDialog(frm);
}

Modeless windows无模式窗口

ShowDialog() is used to display a modal form - a form that retains the focus until it's closed, just like a dialog box. ShowDialog()用于显示模态窗体 - 一种在关闭之前保持焦点的窗体,就像对话框一样。 That's why the method is called ShowDialog() instead of ShowModal() .这就是该方法被称为ShowDialog()而不是ShowModal()

A loader needs to be modeless, so Show should be used instead :加载器需要是无模式的,所以应该使用Show来代替:

public void ShowLoader(Form frm)
{
    cploader.Show(frm);
}

Another difference is that ShowDialog returns a result with the user's choice (OK, Cancel etc) while Show returns nothing.另一个区别是ShowDialog返回带有用户选择(确定、取消等)的结果,而Show返回任何内容。

Modal Loader with notification带通知的模态加载器

If you want to create a modal loader with ShowDialog but still perform some work in the background, you need a way to notify that loader from the background thread.如果你想用ShowDialog创建一个模态加载器,但仍然在后台执行一些工作,你需要一种从后台线程通知该加载器的方法。 You can do that using the Progress class.您可以使用Progress类来做到这一点。

The loader can expose IProgress<T> as a property.加载程序可以将IProgress<T>作为属性公开。 The T parameter can be a simple string or integer showing progress, or a complex entity with progress, a string message and a status indicator. T参数可以是显示进度的简单字符串或整数,也可以是带有进度、字符串消息和状态指示器的复杂实体。 For laziness' sake, let's use string and close the dialog if the value is empty :为了懒惰,让我们使用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;
    }
}

The code that works in the background needs access to that IProgress<string> property.在后台运行的代码需要访问该IProgress<string>属性。 Let's say the code that needs to work in the background is :假设需要在后台工作的代码是:

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("");
}

This code can run in the background and use the loader this way :此代码可以在后台运行以这种方式使用加载器:

var loader=new CPLoader();
var task=Task.Run(()=>DoWork(loader.Progress));
loader.ShowDialog();
await task;

The loader is initialized first, giving us access to the IProgress<T> instance.加载器首先被初始化,让我们可以访问IProgress<T>实例。 The job gets started in the background after that with Task.Run .之后使用Task.Run在后台启动作业。 When it finishes, it sends an empty progress string and the loader's UpdateUI method closed the dialog in response当它完成时,它发送一个空的进度字符串,加载器的UpdateUI方法关闭对话框作为响应

The code that needs to perform work while loading can access that IProgress<string> interface and use it to signal pro加载时需要执行工作的代码可以访问该IProgress<string>接口并使用它来向 pro 发送信号

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM