5

最近、「アプリバー」としてデスクトップの端にドッキングできるウィンドウを WPF アプリケーションに追加しました。ドッキングを行うために使用しているコードは、このスタックオーバーフローの投稿からのものです。

プログラムには、このウィンドウに関連して定義された 3 つのユーザー設定があります。1 つはウィンドウがドッキングされている端で、他の 2 つはLeft&Topプロパティの値です。ウィンドウが閉じられたとき、またはプログラムがシャットダウンされたときに、プログラムが再起動したときにウィンドウが同じ状態と場所で再び開くという考え方です。

私が抱えている問題は、プログラムが開いたときに、ウィンドウが最初に画面上のランダムな場所に表示され (おそらく、ウィンドウが作成されたときに Windows によって割り当てられた座標)、次にドッキングされた位置に移動することです。Trillian など、アプリ バー機能を持つ他のプログラムは、最初からドッキングされた位置に描画されます。ウィンドウがそのように動くのを見るのは少し戸惑います。

ウィンドウからのコードは次のとおりです。

private void AppBarWindow_Activated( object sender, EventArgs e ) {
    if ( Settings.Default.AppBarWindowEdge != ABEdge.None ) {
        AppBarFunctions.SendShellActivated( this );
    }
}

private void AppBarWindow_Closing( object sender, CancelEventArgs e ) {
    Settings.Default.AppBarWindowLeft = Left;
    Settings.Default.AppBarWindowTop  = Top;
    Settings.Default.Save();

    AppBarFunctions.SetAppBar( this, ABEdge.None );

    // Other, app specific code . . .
}

private void AppBarWindow_LocationChanged( object sender, EventArgs e ) {
    if ( Settings.Default.AppBarWindowEdge != ABEdge.None ) {
        AppBarFunctions.SendShellWindowPosChanged( this );
    }
}

private void AppBarWindow_SourceInitialized( object sender, EventArgs e ) {
    if ( Settings.Default.AppBarWindowEdge != ABEdge.None ) {
        SizeWindow( Settings.Default.AppBarWindowEdge == ABEdge.None ? ABEdge.Left : ABEdge.None );
    }
}

private void AppBarWindow_SizeChanged( object sender, SizeChangedEventArgs e ) {
    if ( Settings.Default.AppBarWindowEdge != ABEdge.None ) {
        AppBarFunctions.SendShellWindowPosChanged( this );
    }
}

private void SizeWindow( ABEdge originalEdge ) {
    // App specific code to compute the window's size . . .

    if ( originalEdge != Settings.Default.AppBarWindowEdge ) {
        AppBarFunctions.SetAppBar( this, Settings.Default.AppBarWindowEdge );
    }

    Settings.Default.AppBarWindowLeft = Left;
    Settings.Default.AppBarWindowTop  = Top;
    Settings.Default.Save();
}

このSHAppBarrMessage記事で読んだように、ウィンドウがアクティブになったとき、またはウィンドウの位置とサイズが変更されたときに呼び出す関数を追加しました。呼び出しは動作に影響を与えないようですので、削除する可能性があります。

SourceInitializedおよびイベントは、ウィンドウが表示される前にLoading呼び出されますが、ウィンドウ ハンドルとレイアウトとメジャー パスが完了した後に呼び出されます。ただし、呼び出しが行われる前にウィンドウがレンダリングされているように見えます。そのため、表示されてから所定のAppBarFunctions.SetAppBar位置に移動します。

Leftまた、プロパティとTopプロパティをウィンドウのコンストラクターの設定に保存されている値に設定することにより、ウィンドウをドッキング位置に移動しようとしました。それもうまくいきませんでした。実際には、ウィンドウが最初にドッキングされた位置に描画され、その後明らかにそのデスクトップの端から離れてスペースを空けてから、ドッキングされた場所に戻されたため、さらに悪化しました。

このウィンドウを起動時にドッキング位置に表示し、その後移動しないようにするにはどうすればよいですか?

編集:

問題の原因が見つかったと思います。ウィンドウ(UI スレッド)でメソッドへの呼び出しをスケジュールする直前にAppBarFunctions、メソッド内のクラス コードにコメントがあります。コメントは次のとおりです。ABSetPosDoResizeDispatcher

// This is done async, because WPF will send a resize after a new appbar is added.  
// if we size right away, WPFs resize comes last and overrides us.

どうやらWPFまたはWindowsがウィンドウ用に予約されているスペースからウィンドウを移動しているようです。その後、元に戻します。コードに多くのトレースポイントを追加しましたが、ウィンドウがレンダリングされるまでレンダリングされないことがわかりますその動きが行われます(コードのコメントに記載されているもの)。ウィンドウがレンダリングされた後、コードによってドッキングされた位置に移動されます。

このAppBarFunctionsクラスは、シェルからのメッセージを監視するためのウィンドウ プロシージャ フックを既に追加しています。WM_WINDOWPOSCHANGED のチェックを追加すると、何らかの方法でメッセージの処理を停止できますか? または、Windows / WPF によって実行された移動のプロパティLeftTopプロパティの値を変更して、ウィンドウが目的の場所になるようにすることもできますか?

4

1 に答える 1