C# 在windows窗体中实现类似web应用程序的加载程序
当任何长时间运行的进程在C# 在windows窗体中实现类似web应用程序的加载程序,c#,multithreading,winforms,desktop-application,showdialog,C#,Multithreading,Winforms,Desktop Application,Showdialog,当任何长时间运行的进程在windows窗体中执行时,我正在尝试显示Loader。我已经实现了这方面的代码,但加载程序正在显示,但不在centerprist位置,它将显示在屏幕的中心 代码: CPLoader是我希望在任何进程执行时显示的表单 public class CommonLoader { CPLoader cploader = new CPLoader(); readonly Form form = null; public CommonLoader(Form
windows窗体中执行时,我正在尝试显示Loader
。我已经实现了这方面的代码,但加载程序正在显示,但不在centerprist
位置,它将显示在屏幕的中心
代码:
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");
}
}
}
公共类CommonLoader
{
CPLoader CPLoader=新CPLoader();
只读形式=空;
公共公共加载程序(表格frm)
{
形式=frm;
}
公共void ShowLoader()
{
尝试
{
如果(需要调用表单)
{
尝试
{
cploader=新cploader();
cploader.ShowDialog();
}
抓住
{
Console.WriteLine(“Cp加载程序异常”);
}
}
其他的
{
Thread th=新线程(ShowLoader);
th.IsBackground=false;
th.Start();
}
}
抓住
{
Console.WriteLine(“Cp加载程序异常”);
}
}
///
///此方法将用于在进程停止时隐藏加载程序
///
公共无效HideLoader()
{
尝试
{
if(cploader!=null)
{
睡眠(200);
调用(新操作(cploader.Close));
}
}
抓住
{
Console.WriteLine(“Cp加载程序异常”);
}
}
}
我还尝试了cploader.ShowDialog()
和frm.BeginInvoke(新方法调用程序(委托(){cploader.ShowDialog(表单);}))
如果使用BeginInvoke()
,则无法关闭加载程序。启动屏幕、进度屏幕等在Visual Basic或Delphi桌面应用程序中出现的时间早于web应用程序。它们只是显示在应用程序顶部的无模式窗体/窗口。他们也不需要线程——当时的应用程序大多是单线程的
后台线程无论如何都无法修改UI,这意味着整个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
}
指定父级
不带任何参数的调用将创建父窗口为桌面的窗口。这就是为什么窗口显示在屏幕的中心,而不是应用程序的中心
要指定所有者/父级,只需将其作为owner
参数传递给或即可
以下代码可用于显示以当前表单为中心的对话框:
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
创建模式加载程序,但仍要在后台执行某些工作,则需要一种从后台线程通知该加载程序的方法。您可以使用类来实现这一点
加载程序可以将IProgress
作为属性公开。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
实例。然后在后台使用任务启动作业。运行。当它完成时,它发送一个空的进度字符串,加载程序的UpdateUI
方法关闭对话框作为响应
加载时需要执行工作的代码可以访问IProgress
界面,并使用它向pro发出信号,通过“loader”(加载程序)您是指启动屏幕、进度条还是旋转球?在这方面,Web应用程序实际上模拟桌面应用程序。这样做不需要线程(事实上,线程根本无法触及UI)。只需在当前窗体的顶部显示一个无模式窗体,其中包含您想要显示的内容。这意味着,只需使用Show
而不是ShowDialog()
,并在需要隐藏时调用Hide()
。所有其余的代码在最坏的情况下都会死锁,或者在最好的情况下再次在UI线程中运行-BeginInvoke()
意味着在UI线程上运行此方法
至于居中,您没有发布任何试图在特定位置显示表单的代码,或者表单的属性。唯一相关的代码是cploader=newcploader();cploader.ShowDialog()代码>显示模式窗体而不指定父级。这将创建一个其父级为桌面的对话框。您应该将父窗体作为参数传递给ShowDialog
或Show
@panagiotis kanavos,我已经更新了问题,请查看它。我认为它会阻止进程,直到用户关闭它。我需要在进程执行时显示对话框,完成后自动关闭,无需用户交互。@HirenPatel为什么?你试过了吗?即使ShowDialog()
不会阻塞线程,它也会将焦点保留在表单上<另一方面,显示代码>显示
时不会阻止用户使用同一应用程序中的其他控件或窗体
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;