我有一个长期运行的方法必须在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线程上运行(例如,数据排序,数据过滤)
非常感谢任何提供特定解决方案的人(无论是否有效),但我原来的问题又重新出现了:
有没有办法改变超时时间或以某种方式控制整个“无响应”惨败?
答案 0 :(得分:16)
您可以使用DisableProcessWindowsGhosting
win32功能:
[DllImport("user32.dll")]
public static extern void DisableProcessWindowsGhosting();
这实际上不会阻止窗口冻结,但会阻止标题中的“Not Respongind”文本。
答案 1 :(得分:2)
我担心最简单的解决方案是让你自己的CopyToClipboard()
在你的for循环中,不时地做一个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());
}
答案 2 :(得分:1)
这是因为您在主应用程序线程中同步调用了一个长时间运行的方法。当您的应用程序忙时,它不会响应来自Windows的消息,并且在完成之前标记为(无响应)。
要处理此问题,请进行异步复制,例如使用Task作为最简单的解决方案。
Task task = new Task(() =>
{
gridView.Enabled = false;
gridView.CopyToClipboard();
gridView.Enabled = true;
});
task.Start();
禁用您的网格,以便任何人都无法更改GUI中的值。 您的应用程序的其余部分仍然响应(可能有副作用!)。
答案 3 :(得分:1)
你可以隐藏启动过程,然后检查是否有响应并在完成后将其恢复到视图中......你的启动画面会显示它仍然“响应”。
Process proc = new Process();
proc.StartInfo.FileName = "<Your Program>.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("<YourProcess.exe>");
if (processList.Length == 0)
{
//process completed
timer1.Stop();
break;
}
span = DateTime.Now.Subtract(dStartTime);
}
if (span.Seconds > timeout)
{
Process[] processList = Process.GetProcessesByName("<YourProcess.exe>");
//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);
答案 4 :(得分:1)
有几种可能的方法
gridView.GetSelectedCells()
获取所选单元格,然后异步将其内容放入剪贴板如果您已将GridView
库上传到某处,那将会更有帮助,以便我们可以查看内部。
答案 5 :(得分:1)
我不清楚您的用户是否需要看到“无响应”的屏幕。如果没有必要,您可以尝试在关闭此应用程序的主线程后让应用程序在后台运行;或者你可以最小化应用程序。
如果有必要查看应用程序并使其看起来有效,您是否可以将“复制到剪贴板”功能细分为线程并接受数组或gridview和索引范围。这样做的好处是你的从属进程的主线程永远不会挂起。缺点是人们不喜欢在C#中使用线程和委托。
答案 6 :(得分:1)
好的,你所描述的'Not Responding'和窗口工件只是在你的UI线程上运行长期活动的症状。 UI线程被阻止,因此UI被冻结。没有避免这种情况。说实话,你的应用程序看起来像响应一样“幸运”。
据我所知,这里描述的每个解决方法都只是为了捏造你的UI线程被冻结的事实。不要这样做。修复您的程序,以便不冻结UI线程。
问问自己:我的用户真的是否需要从此视图中复制所有行?是否可以通过某种方式过滤数据来限制行?如果没有,有一个名为MaxRowCopyCount的属性可以限制复制的行数 - 是否可以在不破坏工作流程的情况下利用它?
最后,如果所有其他方法都失败了,是否还有其他可以使用的媒介(可能是中间文件),可以在后台线程上复制哪些数据?
答案 7 :(得分:0)
IsHungAppWindow中记录的超时无法更改。不要使用全局状态来管理本地问题。
您必须优化导致无响应的部分。例如,使用缓存,虚拟网格(DevExpress称之为“服务器模式”),分页,将排序委托给ibindinglistview过滤器,该过滤器执行数据库查询(使用数据库索引)而不是内存中排序(无索引)或{{3所以你只需要在用户粘贴时填充数据。