2017-09-18 2 views
0

Ich habe ein Fenster erstellt, deaktivierten Rahmen und setze SizeToContent = "Height".Automatisches Positionsfenster - 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> 

Wenn ich das Fenster öffne ich es in der rechten unteren Bildschirm positionieren:

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

Manchmal versuche ich, Kinder zu Maingrid, hinzuzufügen und setzen Sie sie wieder, weil Höhe wurde geändert:

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 nachdem die Fensterposition zufällig in der vertikalen Ebene positioniert ist. Nach 5 Sekunden zerstörte ich seine Grenze und versuchte, das Fenster neu zu positionieren

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

und wieder vertikale Position hat einige seltsame Wert.

Position auf dem Bildschirm:

Position on screen

+1

In WPF müssen Sie entweder auf das Rendern warten oder das Layout erzwingen (indem Sie measure/arrangement aufrufen), bevor neue Größen verfügbar sind. Übrigens, benutze 'DispatcherTimer'. – Sinatr

+0

Wie kann ich warten, wenn Fenster gerendert hat? – Vozdr

+0

Ich bin mir nicht sicher, was genau das Problem ist (was genau ist falsch?), Es war mein verrückter Kommentar. Aber wenn das richtig ist, dann genügt 'Dispatcher.Invoke (() => methodToRunAfterRender, DispatcherPriority.Render)'. – Sinatr

Antwort

0

Könnten Sie genauer angeben, was Sie erwarten und versuchen, Ihre Frage zu verbalisieren? Wenn Sie versuchen, Ihre Fenster zu positionieren, warum nicht WindowStartupLocation verwenden?

Wenn Sie WindowStartupLocation auf Manual setzen, wird ein Fenster entsprechend den Eigenschaftswerten Left und Top positioniert. Wenn die Eigenschaften Left oder Top nicht angegeben sind, werden ihre Werte von Windows bestimmt. Einstellung CenterScreen bewirkt, dass ein Fenster in der Mitte des Bildschirms positioniert wird, der den Mauszeiger enthält.

Die Einstellung von WindowStartupLocation auf CenterOwner bewirkt, dass ein Fenster in der Mitte seines Besitzerfensters (siehe Owner) positioniert wird, wenn angegeben ist. Das Besitzerfenster kann entweder ein anderes WPF-Fenster oder ein Nicht-WPF-Fenster sein.

MSDN source

+0

Wie sagt Sinatr, ich muss auf Render warten. Aber ich weiß nicht, wie ich es machen kann ... – Vozdr

+0

Hast du diesen gesehen? https://StackOverflow.com/Questions/10330446/How-to-know-when-a-Control-oder-window-has-been-rendered-drawn-in-wpf – Bartosz

+0

Keine Hilfe für mich .... – Vozdr

0

An der Stelle, wo Sie setposition(); die Fenstergröße nennen noch nicht aktualisiert ist, zu warten, die einfachste Sache zu bekommen tatsächliche Größe für machen ist durch Aktion in Dispatcher-Warteschlange stellen.

Betrachten Sie dieses Beispiel:

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); 
    }; 
} 

hier ich Fenster haben, die zum Inhalt Größen und stackPanel haben.

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

Der Timer fügt neue TextBlock es jede Sekunde.

Nun, wenn ich versuche, Title so zu aktualisieren, dann ist ActualHeight noch alte, nach dem ersten Update der erste Wert 39 ist, und das ist falsch (es sollte 20 + 39 = 59 sein).Dies passiert, weil das Hinzufügen von Kind nicht zu einer sofortigen Neuberechnung von allem und zum Rendern führt. Nein. Stattdessen werden alle diese Aktionen (Messen, Anordnen und Rendern) über Dispatcher in die Warteschlange gestellt, und tritt etwas später auf. So funktioniert WPF.

das Problem zu beheben ich einfach sagen kann, „tun Sie es bitte nach machen“:

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

Ich fand, dass maingrid.ActualHeight tatsächliche Höhe haben, bevor Fenster machen war, und tun, dass:

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

Seine Arbeit gut.