在新进程中运行时,窗口标题中的“无响应”

我有一个必须在UI线程上运行的长时间运行方法 (Devex – gridView.CopyToClipboard()

我不需要UI在复制时响应,我添加了一个启动画面,这样用户就不会觉得无聊了。

当我运行这个程序时一切都很好。

当我运行一个不同的程序时,麻烦就开始了,而这个程序又启动了一个新进程并在其上运行程序。 复制几秒后标题读取(Not Responding)并且鼠标光标显示忙,它当然会在几秒钟内清除但我想摆脱它,因为它给用户误解了程序的感觉是错误的。

有没有办法设置我创建的流程的“超时”?

编辑:

主程序调用以下代码:

 fillsProcess = new Process(); fillsProcess.StartInfo.FileName = Application.ExecutablePath; fillsProcess.Start(); 

在fillsProcess中,当单击某个按钮时,将调用以下代码:

 gridViewToCopy.CopyToClipboard(); 

这行代码需要一段时间来处理,几秒钟后,fillsProcess的窗口看起来没有响应,因为此方法在UI线程上运行。

编辑第二名:

显然(并且非常可以理解)

 gridViewToCopy.CopyToClipboard(); 

不是导致此问题的唯一方法。 许多Devex方法必须在UI线程上运行(例如,数据排序,数据过滤)

所以感谢任何提供特定解决方案的人(无论是否有效),但我的原始问题再次突然出现:

有没有办法改变超时时间或以某种方式控制整个“无响应”的惨败?

您可以使用DisableProcessWindowsGhosting win32函数:

 [DllImport("user32.dll")] public static extern void DisableProcessWindowsGhosting(); 

这实际上并不会阻止窗口冻结,但会阻止标题中的“Not Respongind”文本。

我担心最简单的解决方案是创建自己的CopyToClipboard() ,你在for循环中, CopyToClipboard()做一个Application.DoEvents ,它保持ui线程的响应。

我想DevExpress的大多数许可证都有可用的源代码,因此如果有的话,你可以复制最多的粘贴。

由于您了解数据,因此您可以制作比DevExpress使用的通用程序更简单的程序。

像这样:

 const int feedbackinterval = 1000; private void btnCopy_Click(object sender, EventArgs e) { StringBuilder txt2CB = new StringBuilder(); int[] rows = gridView1.GetSelectedRows(); if (rows == null) return; for (int n = 0; n < rows.Length; n++) { if ((n % feedbackinterval) == 0) Application.DoEvents(); if (!gridView1.IsGroupRow(rows[n])) { var item = gridView1.GetRow(rows[n]) as vWorkOrder; txt2CB.AppendLine(String.Format("{0}\t{1}\t{2}", item.GroupCode, item.GroupDesc, item.note_no??0)); } } Clipboard.SetText(txt2CB.ToString()); } 

这是因为您在主应用程序线程中同步调用长时间运行的方法。 当您的应用程序忙时,它不会响应来自Windows的消息,并且在完成之前标记为(无响应)。

要处理这个问题,请异步复制,例如使用Task作为最简单的解决方案。

 Task task = new Task(() => { gridView.Enabled = false; gridView.CopyToClipboard(); gridView.Enabled = true; }); task.Start(); 

禁用网格,这样任何人都无法更改GUI中的值。 您的应用程序的其余部分仍然响应(可能有副作用!)。

您可以隐藏启动过程,然后检查是否响应并在完成后将其恢复到视图中….您的启动画面将显示其仍然“响应”。

  Process proc = new Process(); proc.StartInfo.FileName = ".exe" proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; 

编辑:您还可以创建一个Timer事件,观察其他进程并滚动您自己的超时逻辑

  DateTime dStartTime = DateTime.Now; TimeSpan span = new TimeSpan(0, 0, 0); int timeout = 30; //30 seconds private void timer1_Tick(Object myObject, EventArgs myEventArgs) { while (span.Seconds < timeout) { Process[] processList = Process.GetProcessesByName(""); if (processList.Length == 0) { //process completed timer1.Stop(); break; } span = DateTime.Now.Subtract(dStartTime); } if (span.Seconds > timeout) { Process[] processList = Process.GetProcessesByName(""); //Give it one last chance to complete if (processList.Length != 0) { //process not completed foreach (Process p in processList) { p.Kill(); } } timer1.Stop(); } } 

EDIT2

您可以使用pInvoke“ShowWindow”来完成隐藏并在启动后显示窗口

 private const int SW_HIDE = 0x00; private const int SW_SHOW = 0x05; [DllImport("user32.dll")] static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); 

有几种可能的方法

  • 隐藏操作期间的主窗体
  • 以某种方式克隆/序列化控件并将其传递给另一个UI调度程序的线程
  • 通过gridView.GetSelectedCells()获取选定的单元格,然后异步将其内容放入剪贴板

如果你已经将GridView库上传到某个地方会更有帮助,这样我们就可以查看内部了。

我不清楚你的用户是否需要看到“无响应”的屏幕。 如果没有必要,您可以尝试在关闭此应用程序的主线程后让应用程序在后台运行; 或者您可以最小化应用程序。

如果有必要查看应用程序并使其看起来正常工作,您是否可以将“复制到剪贴板”function细分为线程并接受数组或gridview和索引范围。 这样做的好处是你的从属进程的主线程永远不会挂起。 缺点是人们不喜欢在C#中使用线程和委托。

好的,您所描述的“无响应”和窗口构件只是在UI线程上运行长期活动的症状。 UI线程被阻止,因此UI被冻结。 没有避免这种情况。 说实话,你的应用程序看起来像响应一样“幸运”。

据我所知,这里描述的每个解决方法都只是为了捏造你的UI线程被冻结的事实。 不要这样做。 修复您的程序,以便不冻结UI线程。

问问自己:我的用户真的需要从这个视图中复制所有行吗? 可以以某种方式过滤数据以限制行吗? 如果没有,有一个名为MaxRowCopyCount的属性可以限制复制的行数 – 可以在不破坏工作流程的情况下利用这些行吗?

最后,如果所有其他方法都失败了,是否还有其他可以使用的介质(可能是中间文件), 可以在后台线程上复制数据?

IsHungAppWindow中记录的超时无法更改。 不要使用全局状态来管理本地问题。

您必须优化导致无响应的部分。 例如,使用缓存,虚拟网格(DevExpress称之为“服务器模式”),分页,将排序委托给ibindinglistviewfilter,该filter执行数据库查询(使用数据库索引)而不是内存中排序(无索引)或实现IAsyncOperation您的剪贴板数据,因此您只需要在用户执行粘贴时填充数据。