";不响应”;在新进程中运行时显示在窗口标题中

本文关键字:显示 窗口标题 进程 运行时 不响应 quot 新进程 | 更新日期: 2023-09-27 18:01:08

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

我不需要UI在复制时做出响应,我添加了一个启动屏幕,这样用户就不会无聊了。

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

当我运行一个不同的程序时,问题就开始了,而这个程序又启动了一个新的进程并在上面运行程序。复制几秒钟后,标题显示(无响应),鼠标光标显示繁忙,当然会在几秒钟内清除,但我想去掉它,因为它会给用户一种误解的感觉,即程序有故障。

有什么方法可以设置我创建的流程的"超时"吗?

编辑:

主程序调用以下代码:

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循环中,不时地执行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());
}

这是因为您在主应用程序线程中同步调用了一个长时间运行的方法。由于应用程序正忙,它不会响应来自窗口的消息,并且在完成之前标记为(未响应)。

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

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

禁用网格,这样就没有人可以更改GUI中的值。应用程序的其余部分保持响应(可能有副作用!)。

您可以隐藏启动流程,然后检查是否响应,并在完成后将其带回视图。。。。你的启动屏幕会显示它仍在"响应"。

 Process proc = new Process();
 proc.StartInfo.FileName = "<Your Program>.exe"
 proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;

编辑:您还可以创建一个定时器事件来监视其他进程,并滚动您自己的超时逻辑

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

第2版

您可以使用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库上传到某个地方,这样我们就可以查看里面了,那会更有帮助。

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

如果有必要查看应用程序并使其看起来正常工作,您可以对"复制到剪贴板"函数进行分段,使其具有线程化,并接受数组或网格视图和索引范围。这样做的好处是,您的从属进程上的主线程永远不会挂起。缺点是人们不喜欢在C#中使用线程和委托。

好吧,您所描述的"未响应"和窗口伪影只是在UI线程上运行长期活动的症状。UI线程被阻止,因此UI被冻结。这是不可避免的。老实说,你的应用程序看起来和它一样响应,这只是"幸运"。

据我所见,这里描述的每一个解决方法都只是一个破解,以掩盖UI线程被冻结的事实。不要这样做。修复你的程序,这样UI线程就不会被冻结。

问问自己:我的用户真的需要复制该视图中的所有行吗?是否可以通过某种方式对数据进行筛选以限制行数?如果没有,则有一个名为MaxRowCopyCount的属性可以限制复制的行数——这可以在不破坏工作流的情况下利用吗?

最后,如果其他一切都失败了,是否有其他介质可以使用(也许是中间文件),在后台线程上可以将数据复制到该介质?

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

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