6

WinForms MDIアプリ内でWPFユーザーコントロールをホストする場合、複数のフォームが互いにオーバーラップしていると、描画の問題が発生し、非常に明確な視覚的アーティファクトが発生します。これらのアーティファクトは、WPFコンテンツをホストする別の子フォームの上にドラッグした後、または子フォームの端をメインのMDI親がドラッグしたときにクリップできるようにすることで、ほとんど表示されます。子フォームのドラッグアンドドロップが完了した後、アーティファクトは通常は残りますが、フォーカスを別のアプリケーションのウィンドウに設定してから、アプリケーションウィンドウに再度フォーカスを戻すと、再描画され、子が表示されるまですべてが正常になります。フォームがもう一度移動されます。問題を示す下の画像を参照してください。

説明されているアーティファクトのスクリーンショット

Microsoftの関係者は、WinForms MDIはすでにMDIの十分なソリューションであり、WPFで再発明する必要はないと主張していますが、明らかな欠点があるため、この方法でWPFアプリを作成しようとしたとは信じられません。

更新:私が省略したいくつかの追加の注意事項は、MdiParentを設定せずにこれらのフォームを作成すると、通常のフォームとして作成され、この問題は発生しないということです。この問題は、WinFormsMDIシナリオに固有のようです。また、私は現在Windows 7 Enterpriseで実行しており、結果がWindows XPでかなり異なる可能性があることを認識していますが、これをテストすることはできませんでした。

更新:私が共有すべきだと思ったこの問題に関する他のいくつかの関連リソースを見つけました。

4

4 に答える 4

9

別の回避策は、ハードウェアアクセラレーションを利用するのではなく、ソフトウェアレンダリングに戻すことです。これは、MSDNフォーラムでのMarcoZhouによる提案でした。

public partial class UserControl1 : UserControl
{
    public UserControl1()
    {
        InitializeComponent();
        this.Loaded += delegate
        {
            var source = PresentationSource.FromVisual(this);
            var hwndTarget = source.CompositionTarget as HwndTarget;
            if (hwndTarget != null)
            {
                hwndTarget.RenderMode = RenderMode.SoftwareOnly;
            }
        };
    }
}

私はこれをテストしましたが、このソリューションは非常にうまく機能しているようです。これまでのところ、FoxPro相互運用シナリオ内でこの問題を解決するために見つけた唯一のソリューションは、最初に投稿したWinFormsと非常によく似ています。今のところ、WinFormsプロジェクトのMDI親ソリューションで元の更新を使用することを計画していますが、WPFコントロールがVisual FoxProでホストされている場合など、他のネイティブ相互運用アプリケーションにはこのソリューションを使用します。もちろん、どちらの場合でもより洗練された解決策が見つかった場合を除きます。

また、私が知っていることから、XPシステムではソフトウェアレンダリングが唯一のオプションであり、通常、Visual FoxPro nore WinFormsは、VistaOS以降でネイティブWPFアプリが行うのと同じタイプのハードウェアアクセラレーションを利用することに注意することが重要です。したがって、このオプションを使用することは、相互運用性に対処する必要がある場合に聞こえるほど悪くはないかもしれません。現在、このソリューションを使用する際の関連する副作用については認識していませんが、副作用がある場合は、それらを真剣に検討する必要があります。

于 2010-04-07T16:29:22.103 に答える
2

まあ、それはちょっとしたハックのように感じますが、私は解決策を見つけたかもしれません。子MDIフォームが移動されるたびに、MDI親でRefreshメソッドを呼び出すと、記録されたアーティファクトが消えるように見えます。ウィンドウをドラッグすると、視覚的には少しぎくしゃくしたように見えますが、元の投稿で示した例よりもはるかに受け入れやすいようです。

private void Form1_Move(object sender, EventArgs e)
{
    this.ParentForm.Refresh();

    System.Diagnostics.Debug.WriteLine(string.Format("Form Moved to: ({0},{1})", this.Left, this.Top));
}

Update()Invalidate()Refresh()などのメソッドを呼び出して移動されていた子ウィンドウだけを更新するなど、同じ方法で多くの組み合わせを試しました。また、MDIの親でこれらの同じメソッドを試しました。ホストされたWPFコントロールのDispatcher.Invoke(DispatcherPriority.Render、...)InvalidateVisual()も同様ですが、これらの他のメソッドはいずれも、特にMDI親でRefresh()を呼び出すことを受け入れません。

子ウィンドウが数ピクセル移動するたびにメインアプリケーションウィンドウ全体を強制的に更新するため、これはおそらく最適なソリューションではないことを認識していますが、現時点では、これが機能する唯一の合理的なソリューションです。他の誰かがこれに対する代替の解決策または改善を持っているならば、私は代わりにあなたの答えを喜んで受け入れます。

于 2010-04-07T15:50:10.840 に答える
2

ビデオドライバを確認し、ハードウェアアクセラレーションを無効にしてみてください。ほとんどのアーティファクトは、ドライバの不良、ビデオカードの故障、または更新を完了するのに十分な時間がないことが原因です。

最初のトラブルシューティング手順:ビデオドライバーを更新します。明らかです、私は知っています。

同様の問題がありました。ビデオカードの設定(NVidiaコントロールパネル)を確認すると、グローバル設定が非常に高く設定されているため、更新間隔が長くなり、時間がかかりすぎると中止される可能性があります。設定をデフォルトに戻すと、ほとんどの問題が解決しました。しかし、GPUを集中的に使用するハッシュプログラムも実行しているため、これが私の残りのアーティファクトの問題の原因である可能性があります。

私が遭遇した別のトラブルシューティング手順は、WPFのハードウェアアクセラレーションを無効にすることです。これは「HKEY_CURRENT_USER / SOFTWARE / Microsoft / Avalon.Graphics」で実行できます。または、アプリケーションで実行できる場合もありますが、これはトラブルシューティング専用です。すべてのWPFアプリケーションで無効になるため、アプリケーション内でこれらを設定しないでください。私はこのレジストリ設定を持っておらず、追加もしなかったので、それで成功するかどうかはわかりませんが、多くの人がこれで問題が解決したと言います。また、一部のアプリケーションではこのオプションを使用できることに注意してください。使用可能な場合は無効にしてみてください。

もう1つのトラブルシューティング手順は、ビデオカードがレンダリングに適したティアレベルであることを確認することです。DX9以上をサポートするカードであれば十分ですが、他の要因が関係しているため(私の場合のように)、リストにあるからといって、それが目的に適しているとは限りません。

最後に、Visual Profiler(Windows SDKの一部)やその他のツールを使用して、グラフィックス機能に関連するパフォーマンスが不足しているWPFで何が起こっているかをより正確に判断できます。

階層レベルのメモとWPFパフォーマンス情報のレンダリング-> http://msdn.microsoft.com/en-us/library/vstudio/ms742196 (v=vs.90).aspx

これが誰かを助けることを願っています。

-ライアン・ストラスブール

于 2013-01-17T18:42:15.087 に答える
0

ユーザーコントロールまたはウィンドウロードイベント;

this.WindowState = System.Windows.WindowState.Minimized;

this.WindowState = System.Windows.WindowState.Normal;

それは悪い解決策に見えるかもしれません。頭を壁にぶつける必要はありません。

トルコのことわざは言う:最高のコードはコードが実行されていることです:)

于 2015-08-25T15:20:47.967 に答える