1

私はC#のプログラムの初心者です。移動が完了するまでUIをスタックせずにメインUIでラベルを移動するスレッドを作成したいのですが、何かを作成しましたが、問題が何であるかを教えてくれませんでした

private void button1_Click(object sender, EventArgs e)
    {
        Thread t = new Thread(Movelb);
        t.IsBackground = true;
        t.Start();enter code here
    }


private void DOsomeThing()
        {
            label2.Visible = true;
            label2.Location = new Point(0, 205);
            for (int i = 0; i < 533; i++)
            {
                label2.Location = new Point(i, 205);
                Thread.Sleep(10);
            }
            label1.Text="false";
        }
private void Movelb()
            {
                if (this.InvokeRequired)
                {
                    threadDel d = new threadDel(DOsomeThing);
                    this.BeginInvoke(d);
                }
                else
                    DOsomeThing();


    }
4

4 に答える 4

1

最初にイベント モデルを理解する必要があります。Windows、Android、Linux などのイベント駆動型環境では、通常、座標のアニメーションやその他のプロパティなどの「自動」タスクは、アニメーション/プロセスを進めるハンドラーにイベントを再送信し続けるタイマーを使用して実行されます。特定の例では、ラベルを移動する必要がある場合は、Widows.Forms.Timer を使用します。UI スレッドが停止し、アプリがフリーズしたりぎくしゃくしたりするため、時間のかかるタスクでイベントを処理する UI スレッドをブロックすることは適切ではありません。一方、スレッドを追加すると多くの場合に役立つ場合が多くありますが、それはいつですか? あなたの場合ではありません。再描画と比較してCPUの点で何もないラベルの座標のみを変更するため、余分なスレッドを使用したソリューションは、タイマーを使用するよりも効率が低く、はるかに複雑です。

イベントの仕組み

OS には、キーボード、マウス、およびその他のイベントによって中断される無限ループが内部にありますが、ループは Windows (または Android または XWidnws...) をシャットダウンするまで無期限にスピンします。ループの最後で、OS は「生の」マウス/キー イベントを確認し、それらを適切なアプリケーション キューにディスパッチします。トップにあるすべてのアプリウィンドウリストを検査することでそれを認識し、そのため、そのようなX、Yマウス座標の下にあるウィンドウ/アプリを認識します。イベントがアプリにディスパッチされると、それを非常に高速に処理し、キューで別のイベントを探す必要があります (キューは UI スレッド/Windows にバインドされています)。

タイマーのしくみ タイマーは、OS が内部の「無限ループ」から定期的に送信し続ける特別な種類のイベントです。OS は、通知を要求されたアプリとその頻度を追跡します。時間になると、Windows キューに WM_TIMER (MS Windows の場合) が追加されます。この方法では、何もブロックしませんが、X ミリ秒ごとに呼び出されるコード内のメソッドを取得します。.NET Timer クラスを使用する場合、これは Windows ユーザー API の CreateTimer() KillTimer() (正確な機能名は思い出せません) の単なるラッパーです。.NET タイマーは、WM_TIMER を飲み込み、C# イベント/デリゲートを呼び出す方法も認識しています。

これが役立つことを願っています!

于 2012-12-29T19:00:55.663 に答える
1

スレッドを使用してフォームにペイントしたり、フォームの内容を変更/更新したりしないでください。Windows プログラミングで推奨されるパラダイムは、フォームまたはウィンドウごとに 1 つのスレッドです。別のスレッドから実行されるフォームを作成する場合は、

  1. 最初に新しいスレッドを作成します
  2. 新しいスレッドでフォームを作成します

このようにして、新しいスレッドは新しいフォームのメッセージ ハンドラーとして機能します。ただし、その場合でも、そのスレッド内でフォームのすべての操作を行う必要があります (フォームが別のスレッドで実行されている別のフォームの内容を変更する場合は、追加のスレッドセーフな通信トリックが必要になる場合があります)。

ウィンドウの内容をアニメーション化するSystem.Windows.Forms.Timerには、代わりに使用する必要があります。これは、フォームのスレッドで他のメッセージとロックステップで実行されます。for()ただし、ループ コンストラクトではなく、ステート マシンとしてアニメーションを再実装する必要があります。これは、Label 位置の変数を Form クラスに埋め込む必要があることを意味します。これにより、Timer メッセージの呼び出し全体で更新を保持できます。

于 2012-12-29T19:08:11.017 に答える
0

あなたのコードは何の役にも立ちません。新しいバックグラウンド スレッドを開始するだけで、デリゲートが呼び出され、同じ UI スレッド (開始されたバックグラウンド スレッド) で実行されます。

つまり、ラベルを移動すると、バックグラウンド スレッドから実行できない再描画が発生するため、ワーカー スレッドでラベルを移動することはできません。

于 2012-12-29T18:00:35.493 に答える