に設定SizeToContent
するとWidthAndHeight
、WindowStartupLocation="CenterOwner"
正しく動作しません。新しいウィンドウの中心が親の所有者の中心にあるのではなく、子ウィンドウの左上隅が親の中心にあるように見えます。削除すればSizeToContent
、すべて問題ありません。なにが問題ですか?
4 に答える
さて、レイはこれを見事に立てました。簡単に言うと、彼が言いたいのは、イベントでコントロールのコンテンツを設定しているということです。これにより、ウィンドウの配置が完了した後、&(および& )Loaded
がリセットされます。Height
Width
ActualHeight
ActualWidth
これを修正するには、2つの方法があります。
- コンテンツ値設定コードをコンストラクターに移動する、または、
Window
次のように、に従って位置を再計算する簡単なメソッドを追加し、イベントOwner
の最後にこのメソッドを呼び出します。Loaded
..。
private void CenterOwner()
{
if (Owner != null)
{
double top = Owner.Top + ((Owner.Height - this.ActualHeight) / 2);
double left = Owner.Left + ((Owner.Width - this.ActualWidth) / 2);
this.Top = top < 0 ? 0 : top;
this.Left = left < 0 ? 0 : left;
}
}
ウィンドウが表示されると、ウィンドウが測定され、測定プロセスによって計算されたウィンドウのandをWindowStartupLocation
使用して処理されます。ActualWidth
ActualHeight
あなたが説明した動作は、Show() または ShowDialog() の呼び出し時にゼロまたは比較的小さいと測定され、後でゼロ以外の値に設定されることを示していますActualWidth
。ActualHeight
これは、たとえば、Loaded
イベントでのみ設定される DataContext を使用してウィンドウのコンテンツが構築されている場合に発生する可能性があります。が呼び出されたときShow()
、ウィンドウはLoaded
まだ開いていないため、データがありません。後でLoaded
イベントが発生すると、DataContext が設定され、ウィンドウの内容が更新されますが、配置は既に行われています。
他にも多くのシナリオがあります。たとえば、Dispatcher.BeginInvoke 呼び出しを使用して埋められたコンテンツ、別のスレッドから埋められたコンテンツ、遅延または非同期のバインディングなどです。
基本的に、呼び出された瞬間にウィンドウのコンテンツが通常よりも小さくなる可能性があるものを探してShow()
修正する必要があります。
バインドされた動的コンテンツは、ほとんどの場合、Gui で直接レンダリングされますが、GUI でディスパッチされることもあります。タイマーおよびその他のスレッドは、(MVVM) プロパティ変更イベントを開始できます。WPF ディスパッチャ キューの優先度を配置するため、レンダリングが近いうちに行われることは確かですが、保証されるわけではありません。そのため、レンダリングがいつ終了したかを知ることはできず、WPF は処理の順序について何かを言うことができません。
秘訣は、WPF キューが空であることを待つことです。次に、WPF がコードを処理する時間があることを確認します。つまり、ウィンドウの ShowDialog 呼び出しを遅らせます。
そのため、 MVVM の動的コンテンツ変更やその他の動的変更を実行するために、必要なすべての時間を GUI メイン スレッドに与えてください。位置を手動で計算しようとしないでください。マルチ ディスプレイをサポートするには非常に複雑です。このコードを試してウィンドウを開くと、WPF がすべての操作を終了したときにウィンドウのみが開きます。
win.Dispatcher.Invoke(new Action(() => win.ShowDialog()), DispatcherPriority.ApplicationIdle);
あなたの質問は少しあいまいです。どのウィンドウ (「親」または「子」) で SizeToContent と WindowStartupLocation を設定していますか?
プロジェクトに 2 番目のウィンドウを作成し、その SizeToContent と WindowStartupLocation を説明どおりに設定すると、目的の結果が得られます。
あなたが忘れているかもしれないと私が考えることができる唯一のことは、実際に子ウィンドウにその所有者が誰であるかを伝えることです:
Window2 w = new Window2();
w.Owner = this; // "this" being the parent window
w.ShowDialog();
または、より簡潔に:
new Window2 { Owner = this }.ShowDialog();