14

UI スレッドで実行する必要がある実行時間の長いメソッドがあります。(デベックス - gridView.CopyToClipboard())

コピー中に UI をレスポンシブにする必要はありません。スプラッシュ スクリーンを追加して、ユーザーが退屈しないようにしました。

このプログラムを実行すると、すべてうまくいきます。

別のプログラムを実行すると、新しいプロセスが開始され、その上でプログラムが実行されると、問題が発生します。タイトルをコピーして数秒後に (応答なし) と表示され、マウス カーソルがビジー状態になっている場合は、もちろん数秒以内にクリアされますが、ユーザーにプログラムの誤解を与えるので、それを取り除きたいと思います。が故障しています。

作成したプロセスの「タイムアウト」を設定する方法はありますか?

編集:

メイン プログラムは次のコードを呼び出します。

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

fillsProcess では、特定のボタンがクリックされると、次のコードが呼び出されます。

gridViewToCopy.CopyToClipboard();

このコード行の処理には時間がかかり、数秒後に fillsProcess のウィンドウが応答しなくなったように見えます。これは、このメソッドが UI スレッドで実行されるためです。

2番目の編集:

どうやら(そして本当に非常に理解できるように)

gridViewToCopy.CopyToClipboard();

この問題を引き起こす唯一の方法ではありません。多くの Devex メソッドは UI スレッドで実行する必要があります (例: データの並べ替え、データのフィルタリング)

したがって、特定の解決策を提供してくれた人に感謝します (それが機能したかどうかに関係なく) が、私の元の質問が再び表示されます。

タイムアウト時間を変更したり、何らかの方法で「応答なし」の大失敗全体を制御したりする方法はありますか?

4

8 に答える 8

17

DisableProcessWindowsGhostingwin32関数を使用できます:

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

これは実際にはウィンドウがフリーズするのを防ぎませんが、タイトルに「応答しません」というテキストが表示されるのを防ぎます。

于 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

非表示のプロセスを開始し、応答するかどうかを確認し、完了したら表示に戻すことができます。スプラッシュ画面にはまだ「応答中」と表示されます。

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

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);
于 2013-03-06T09:57:08.490 に答える
1

これは、メインのアプリケーションスレッドで長時間実行されているメソッドを同期的に呼び出すためです。アプリケーションがビジーであるため、Windowsからのメッセージに応答せず、終了するまで(応答なし)としてマークされます。

これを処理するには、非同期でコピーを実行します。たとえば、最も簡単なソリューションの1つとしてタスクを使用します。

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

        task.Start();

グリッドを無効にして、GUIで誰も値を変更できないようにします。アプリケーションの残りの部分は応答性を維持します(副作用がある可能性があります!)。

于 2013-02-28T15:03:03.880 に答える
1

いくつかの可能なアプローチがあります

  • 運用期間中はメインフォームを非表示にする
  • 何らかの方法でコントロールを複製/シリアル化し、別の UI ディスパッチャーを使用してスレッドに渡します
  • 選択したセルを取得し、gridView.GetSelectedCells()その内容を非同期的にクリップボードに配置します

ライブラリをどこかにアップロードしていただければ、GridView内部を確認できるようになります。

于 2013-03-11T17:56:45.077 に答える
1

ユーザーが「応答しない」画面を見る必要があるかどうかは不明です。不要な場合は、このアプリのメイン スレッドを閉じた後、アプリケーションをバックグラウンドで実行できるようにしてみてください。または、アプリを最小化することもできます。

アプリケーションを表示し、動作しているように見せる必要がある場合は、スレッド化され、配列またはグリッドビューとインデックス範囲のいずれかを取得するように、「クリップボードにコピー」機能をセグメント化できますか。これの利点は、従属プロセスのメイン スレッドが決してハングしないことです。欠点は、人々が C# でスレッド化とデリゲートを操作することを好まないことです。

于 2013-03-11T18:40:09.880 に答える
1

さて、あなたが説明した「応答なし」とウィンドウ アーティファクトは、UI スレッドで長期的なアクティビティを実行した場合の症状にすぎません。UI スレッドがブロックされているため、UI がフリーズしています。これを避けることはできません。正直なところ、アプリケーションがこれほどレスポンシブに表示されるのは「幸運」です。

私が見る限り、ここで説明されているすべての回避策は、UI スレッドがフリーズしているという事実をごまかすためのハックにすぎません。これをしないでください。UI スレッドがフリーズしないようにプログラムを修正します。

自問してみてください: ユーザーは本当にこのビューからすべての行をコピーする必要がありますか? 行を制限するために何らかの方法でデータをフィルタリングできますか? そうでない場合は、コピーされる行数を制限する MaxRowCopyCount というプロパティがあります。ワークフローを中断せずにこれを利用できますか?

最後に、他のすべてが失敗した場合、バックグラウンド スレッドでデータをコピーできる他のメディア (おそらく中間ファイル) を使用できますか?

于 2013-03-12T15:50:59.343 に答える
0

IsHungAppWindow に記載されているタイムアウトは変更できません。ローカルの問題を管理するためにグローバルな状態を使用しないでください。

無反応の原因となる部分を最適化する必要があります。たとえば、キャッシング、仮想グリッド (DevExpress では「サーバー モード」と呼ばれます)、ページングを使用し、並べ替えをメモリ内並べ替え (インデックスなし) の代わりにデータベース クエリを実行する (データベース インデックスを使用する) ibindinglistview フィルターに委任するか、IAsyncOperationを実装します。これにより、ユーザーが貼り付けを行うときにのみデータを入力する必要があります

于 2013-03-12T16:28:00.787 に答える