0

コンパスを描画するWPFアプリがあります。目盛りとラベルが付いた大きなリングがあります。コンパスのグラフィックのオンとオフを切り替えるチェックボックスがあります。私が最初にアプリを起動したとき、コンパスは即座にオンとオフになります。

一方、ローカルデータベースからデータを取得し、それを使用してオーバーレイグラフィックをレンダリングするコンボボックスがあります。このコンボボックスを使用した後、コンパスグラフィックスはすぐに切り替わりません。実際、チェックボックスをクリックするたびに、UIは約4秒間完全にフリーズします。

WPF用のウィンドウパフォーマンスプロファイリングツールを使用してアプリのプロファイリングを試みました。チェックボックスをオンにすると、アプリがフリーズしただけでなく、プロファイラーもフリーズしました。グラフは後で「追いついた」が、これは何かが深刻に間違っているに違いないことを私に教えてくれる。

問題のあるグラフィックは目盛り(数字のラベルではない)であることがわかりました。それらを排除すると、フリーズの問題は止まります。それらを360からたとえば36に減らしても、アプリはフリーズしますが、時間は短くなります。繰り返しになりますが、目盛りがいくつあっても、アプリが最初に起動するとすぐに切り替わります。

私の質問は、コンパスグラフィックのトグルが瞬時からひどく遅くなる理由をどのように理解するのですか?広範囲にわたるプロファイリングとデバッグを試しましたが、一部の目盛りに可視性を設定するとアプリがフリーズする理由を思い付くことができません。

編集

さて、私はアプリからすべてを取り除き、必要不可欠なものだけを取り除き、それを圧縮して、Sendspaceにアップロードしました。リンクは次のとおりです(約143Kです)。

http://www.sendspace.com/file/n1u3yg

[注:誤ってバナー広告をクリックしないでください。実際のダウンロードリンクははるかに小さく、ページの下部にあります。]

2つのリクエスト:

  1. マシンで問題が発生しましたか?Compass.exe(bin \ Release内)を開いて、チェックボックスをすばやくクリックしてみてください。コンパスの目盛りは、遅れることなくオンとオフを切り替える必要があります。次に、コンボボックスから項目を選択し、チェックボックスをすばやくもう一度クリックしてみます。私のマシンでは、非常に動作が遅く、高速クリックを停止した後、グラフィックが追いつくまでに数秒かかります。

  2. ラグが発生した場合、この奇妙な動作を引き起こしている可能性のあるコードに何かがありますか?コンボボックスは何にも接続されていませんが、コンボボックスからアイテムを選択すると、ウィンドウ上の他のグラフィックの将来のパフォーマンスに影響するのはなぜですか?

4

1 に答える 1

3

ViewModelANTSは特定のパフォーマンスの「ホットスポット」を示していませんが、すべてのティックに個々のティックの処理を担当するがあり、それらのティックを個別にビューにバインドしているように見えるため、テクニックに少し欠陥があると思います。コンパス全体が表示または非表示になるたびに同様のイベントを発生させる、これらのティックの720ビューモデルを作成することになります。また、このフィールドにアクセスするたびに、新しいLineGeometryを作成します。

このようなカスタム描画の状況でWPFに推奨されるアプローチは、を使用してDrawingVisual、WPFのレンダリングシステムの保持モードの側面を採用することです。この手法について説明しているグーグル可能なリソースはいくつかありますが、要点は、コンパスクラスがから継承することを宣言することと、それを継承してコンパスをレンダリングするために使用FrameworkElementするいくつかの小さなクラスです。DrawingVisualこの手法を使用しても、ViewModelでコンパスの動作を駆動することはできますが、コンパスの各部分に個別のビューモデルを設定することはできません。コンパスをベゼル、矢印、視力などの部分に分解する傾向がありますが、問題には別のアプローチが必要になる場合があります。

class Compass : FrameworkElement
{
    private readonly List<ICompassPart> _children = new List<ICompassPart>();

    public void AddVisualChild(ICompassPart currentObject)
    {
        _children.Add(currentObject);
        AddVisualChild((Visual)currentObject);
    }

    override protected int VisualChildrenCount { get { return _children.Count; } }

    override protected Visual GetVisualChild(int index)
    {
        if (index < 0 || index >= _children.Count) throw new ArgumentOutOfRangeException();

        return _children[index] as Visual;
    }

    override protected void OnRender(DrawingContext dc)
    {
        //The control automatically renders its children based on their RenderContext.
        //There's really nothing to do here.
        dc.DrawRectangle(Background, null, new Rect(RenderSize));
    }
}

class Bezel : DrawingVisual
{
   private bool _visible;

   public bool Visible {
   {
     get { return _visible; }
     set
     {
        _visible = value;
        Update();
     }
   }

   private void Update()
   {
       var dc = this.RenderOpen().DrawingContext;
       dc.DrawLine(/*blah*/);
       dc.Close();
   }
}
于 2012-04-12T22:05:06.983 に答える