2

私はリアルタイムのWPF/Silverlight(および間もなくWP7)視覚化コンポーネントに取り組んでおり、ゲームループスタイルでコンポーネント全体を強制的に再描画するための最良のソリューションを探しています。再描画はオンデマンドである必要がありますが、再描画呼び出しでメッセージポンプをバックアップしたくありません。コンポーネントの描画のほとんどは、非WPFプリミティブ(Bitmap Interop、Direct2Dなど)を使用して行われるため、コードはInvalidateVisualを使用せず、その結果、現在は次のようになります。

// Pseudocode, doesnt compile, just to convey the meaning
public void InvalidateElement()
{
    if (CurrentlyDrawing)
        return;

    Dispatcher.BeginInvoke(() => 
    {
        CurrentlyDrawing = true;

        DoDrawInternal();

        CurrentlyDrawing = false;            
    }
}

さて、これは素晴らしいです。InvalidateElementを何度も呼び出すと、応答性が良くなります。ただし、私がやりたいのは、データを視覚化コンポーネントにできるだけ速くプッシュできるようにすることですが、コンポーネントが描画できる場合にのみ描画し、入力ストリームが完了した後はデータに追いつくために描画を続けないようにします。

いいえ、OnRenderをオーバーライドできません。WPF内で非WPF描画を使用しています;-)

基本的に私が欲しいのは、WindowsFormsの古いInvalidate()/ OnPaintのようなもの、さらにはDirectXのゲームループのようなものです。

現時点では、データを視覚化コンポーネントに高速でプッシュする外部スレッドがある場合、データのプッシュを停止すると、コンポーネントの描画が停止する前に、さらに20秒分の更新が行われるという状況になります。データが入ったらすぐに描画をやめたいです。

私が持っていたもう1つのアイデアは、視覚化コンポーネントでCompositionTarget.Renderingを処理してから、データをプッシュするためのある種の基本的なキューを実装し、Renderingイベントがこのデータをできるだけ速く消費することでした。

要約すれば

WPF視覚化コンポーネントVと、1msごとにデータをプッシュするデータソースDがある場合、Dのデータレートに関係なく、Vが30FPS(またはそれが実行できるもの)でデータを描画し、チャンクで更新することをどのように確認できますか? DirectXでゲームレンダリングループがどのように機能するのでしょうか。

データが停止すると、Vはこれまでのすべてを一度に再描画する必要があります。データが速すぎる場合、Vはそれを補うために一度に大きなチャンクを描画します。

さらに情報が必要な場合は、喜んで共有させていただきます。今、私は簡単な修正があるかどうかを判断するための概要を投稿しましたが、コード例を含むより完全なQをリクエストに応じて提供できます。

よろしくお願いします、

4

5 に答える 5

3

CompositionTarget.Renderingイベントでのレンダリングと、無効化された状態でのスロットルを検討することをお勧めします。

Silverlightゲームループの例(F#):

/// Run game
let runGame () =
    let state = gameState.GetEnumerator()
    let rate = TimeSpan.FromSeconds(1.0/50.0)
    let lastUpdate = ref DateTime.Now
    let residual = ref (TimeSpan())
    CompositionTarget.Rendering.Add (fun x -> 
        let now = DateTime.Now
        residual := !residual + (now - !lastUpdate)
        while !residual > rate do
            state.MoveNext() |> ignore
            residual := !residual - rate
        lastUpdate := now
    )

ゲームをプレイする:http://trelford.com/blog/post/LightCycles.aspx

ソースを読む:https ://bitbucket.org/ptrelford/lightcycles

于 2012-01-06T08:07:28.993 に答える
1

30FPSで実行されているディスパッチタイマーを使用して、現在のデータのスナップショットを取り、タイマーティックごとにレンダリングすることを考えましたか?何も変更されていない場合に再描画を回避したい場合は、LastChangedおよびLastRenderedのタイムスタンプを保持し、LastChanged>LastRenderedの場合にのみ実際の再描画を実行できます。基本的に、データの更新とデータのレンダリングは互いに分離されています。主な秘訣は、レンダリングスレッドがデータをレンダリングしたいときに、データの一貫したスナップショットを何らかの方法で取得できるようにすることです(つまり、何らかのロックが必要になります)。

于 2012-01-05T23:44:41.387 に答える
1

私は最近、スタイルのようなゲームループを必要とするプロジェクトに取り組んでいました。私の例は純粋にF#ですが、C#でもその方法を理解できます。相互運用コードを使用してタイマーを初期化し、以下のリンクに示すようにイベントをフックすることもできます。

http://dl.dropbox.com/u/23500975/Demos/loopstate.zip

サンプルでは、​​再描画の方法は示されていません。500ミリ秒ごとに基になるストックデータが更新されるだけです。WPFを使用したあらゆる種類の描画メカニズムでほぼ機能するはずです。中心的なアイデアは、構成可能なイベントを使用することです。F#では、イベントは第一級市民+ IObservable(C#のリアクティブ拡張)であるため、一連のイベントまたは単一のイベントを返す関数を簡単に構成できます。Observable.await関数があります。この関数は、Observableを受け取り、戻る状態もあります。

            eventSource
            |> Observable.await(fun (t:State.t) e ->
                // return the modified state back on every check or in the end
                match e with
                // start button click
                | Choice1Of3(_) ->
                    {t with start=true}

                // stop button click
                | Choice2Of3(_) ->
                    {t with start=false}

                // timer tick event,
                | Choice3Of3(_) ->
                    if t.start = true then
                        handleStockUpdate(t)
                    else t
            ) (state)

ここではいくつかのFP用語を使用しましたが、ここでは通常のC#(OO)の方法で問題なく機能するはずです。

お役に立てれば!

-ファハド

于 2012-01-06T12:56:09.883 に答える
1

CompositionTarget.RenderingWPFがUIをレンダリングする直前にトリガーされるイベントをリッスンし、そこで描画を行うことができます。

もう1つのヒント..InvalidateVisuals()は、Form.Invalidate()とは異なり、コストのかかる再レイアウトも発生します。Form.Invalidate()のようなものが必要な場合は、DrawingGroup(またはビットマップイメージ) "backingStore"を作成し、OnRender()中にDrawingContextに配置して、必要に応じて更新します。WPFは、UIを自動的に更新して再描画します。

于 2017-06-08T04:21:04.260 に答える
0

WPF以外の要素を使用して描画していて、WinFormsによって提供されたInvalidate()メソッドが必要な場合に、フロントエンドにWPFを使用する理由がわかりません。WinFormsを使用するようにUIを切り替えることはできませんか?

于 2012-01-05T23:43:31.957 に答える