14

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

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

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

当我运行另一个程序时,麻烦就开始了,而该程序又启动了一个新进程并在其上运行该程序。复制标题几秒钟后显示(未响应)并且鼠标光标显示忙碌,它当然会在几秒钟内清除但我想摆脱它,因为它给用户一种误解的感觉程序有故障。

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

编辑:

主程序调用如下代码:

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

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

gridViewToCopy.CopyToClipboard();

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

编辑第二个:

显然(而且真的很容易理解)

gridViewToCopy.CopyToClipboard();

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

因此,感谢任何提供特定解决方案(有效或无效)的人,但我原来的问题再次出现:

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

4

8 回答 8

17

您可以使用DisableProcessWindowsGhostingwin32 功能:

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

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

于 2013-03-13T09:01:03.677 回答
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());
}
于 2013-03-13T08:50:46.153 回答
1

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

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

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

        task.Start();

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

于 2013-02-28T15:03:03.880 回答
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();
        }
    }

编辑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);
于 2013-03-06T09:57:08.490 回答
1

有几种可能的方法

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

如果您将GridView库上传到某个地方会更有帮助,以便我们可以查看内部。

于 2013-03-11T17:56:45.077 回答
1

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

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

于 2013-03-11T18:40:09.880 回答
1

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

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

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

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

于 2013-03-12T15:50:59.343 回答
0

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

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

于 2013-03-12T16:28:00.787 回答