2017-09-18 126 views
0

我創建了一些窗口,禁用了邊框並設置了SizeToContent =「Height」。自動定位窗口 - WPF

XAML:

<Window Title="info" Width="350" ResizeMode="NoResize" WindowStyle="None" Opacity="1" Background="{x:Null}" AllowsTransparency="True" SizeToContent="Height"> 
    <Grid> 
    <StackPanel Name="maingrid" Background="AliceBlue"> 
    </StackPanel> 
    </Grid> 
</Window> 

當我打開這個窗口,我在右側屏幕底部放置它:

private void setposition() 
{ 
    var primaryMonitorArea = SystemParameters.WorkArea; 
    this.Left = primaryMonitorArea.Right - this.Width; 
    this.Top = primaryMonitorArea.Bottom - this.Height; 
} 

有時候我嘗試給孩子添加到maingrid,並再次將其重新定位,因爲身高已更改:

Border brd = new Border(); 
DockPanel.SetDock(brd, Dock.Top); 
brd.Margin =new System.Windows.Thickness(0,5,0,0); 
DockPanel dpanel = new DockPanel(); 
System.Windows.Controls.Label header = new System.Windows.Controls.Label(); 
header.Content = "test"; 
DockPanel.SetDock(header, Dock.Top); 
dpanel.Children.Add(header); 
brd.Child = dpanel; 
maingrid.Children.Add(brd); 
setposition(); 
System.Windows.Forms.Timer tmer = new System.Windows.Forms.Timer(); 
tmer.Tick += (sender, e) => timertick(brd, tmer); 
tmer.Interval = 5 * 1000; 
tmer.Enabled = true; 

A讓窗口位置隨機定位在垂直平面上。 5秒鐘後,我破壞了其邊界,並試圖重新定位窗口

private void timertick(Border brd, System.Windows.Forms.Timer timer) 
{ 
    maingrid.Children.Remove(brd); 
    timer.Enabled = false; 
    setposition(); 
    timer.Dispose();   
} 

,再次垂直位置有一些奇怪的值。

的位置在屏幕上:

Position on screen

+1

在WPF中,您必須先等待渲染或強制佈局(通過調用measure /自己安排)才能使用新的大小。順便說一下,使用「DispatcherTimer」。 – Sinatr

+0

如何在窗口渲染時等待? – Vozdr

+0

我不確定究竟是什麼問題(究竟是什麼錯誤?),這是我的堅果評論。但是,如果這是正確的猜測,那麼只需執行'Dispatcher.Invoke((=)=> methodToRunAfterRender,DispatcherPriority.Render)。 – Sinatr

回答

0

你能指定更精確的你所期望的,並嘗試用語言表達你的問題?

如果您試圖定位您的窗口爲什麼不使用WindowStartupLocation

設置WindowStartupLocation手動導致根據其左和Top屬性值進行定位的窗口。如果未指定Left或Top屬性,則其值由Windows確定。 設置CenterScreen會使窗口位於包含鼠標光標的屏幕中央。

設置WindowStartupLocation到CenterOwner使窗口是 定位在其所有者窗口(見所有者)的中心,如果指定 。所有者窗口可以是另一個WPF窗口或非WPF窗口。

MSDN source

+0

怎麼說Sinatr,我需要等待渲染。但我不知道我該怎麼做...... – Vozdr

+0

你見過這個嗎? https://stackoverflow.com/questions/10330446/how-to-know-when-a-control-or-window-has-been-rendered-drawn-in-wpf – Bartosz

+0

沒有幫助.... – Vozdr

0

在你打電話setposition();窗口的大小尚未現實化的地方,最簡單的事情來獲得實際大小是等待通過將行動統一到調度隊列渲染。

考慮這個例子:

public MainWindow() 
{ 
    InitializeComponent(); 
    Loaded += (s, e) => Title = $"{ActualHeight}"; // 39 
    var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1), IsEnabled = true }; 
    timer.Tick += (s, e) => 
    { 
     stackPanel.Children.Add(new TextBlock { Text = "123", Width = 200, Height = 20 }); 
     Title = $"{ActualHeight}"; // 39, 59, 79 ... wrong 
     // below is correct way, displays 59, 79 ... 
     //Dispatcher.Invoke(() => Title = $"{ActualHeight}", DispatcherPriority.Render); 
    }; 
} 

這裏我有窗口,大小對內容和有stackPanel

<Window SizeToContent="Height" Width="200" ...> 
    <StackPanel x:Name="panel" /> 
</Window> 

計時器每秒鐘都會給它添加新的TextBlock

現在,如果我嘗試更新Title這樣,那麼ActualHeight仍然是舊的,第一次更新後的第一個值是39,這是錯誤的(應該是20 + 39 = 59)。發生這種情況是因爲添加子項不會立即重新計算所有內容並進行渲染。不是。所有這些行爲(措施,安排和呈現)都是通過調度員排隊的,發生在一段時間後。這就是WPF的工作原理。

要解決這個問題,我可以簡單地告訴「請做渲染後」

Dispatcher.Invoke(() => ..., DispatcherPriority.Render); 
0

我發現,maingrid.ActualHeight有實際高度窗口已經呈現面前,這樣做:

this.Top = primaryMonitorArea.Bottom - maingrid.ActualHeight; 

它的工作很好。