2009-07-04 14 views
17

Desidero impostare la dimensione iniziale del client della finestra WPF. Non vedo un modo semplice per farlo.Come impostare ClientSize all'avvio della finestra WPF?

In particolare, quando si apre la finestra, desidero che sia dimensionato in modo tale che il suo contenuto possa adattarsi senza bisogno di barre di scorrimento. Ma dopo che è stato mostrato, voglio che la finestra sia liberamente ridimensionabile (più grande o più piccola).

Se si impostano gli attributi Larghezza e Altezza sul mio elemento Finestra, questo imposta la dimensione non client (esterna), che non è utile. Una volta che la barra del titolo e i bordi di ridimensionamento mangiano in quello spazio, l'area client non sarà più abbastanza grande per il suo contenuto e avrò barre di scorrimento. Potrei compensare scegliendo una dimensione più grande, ma sia l'altezza della barra del titolo che lo spessore del bordo sono personalizzabili dall'utente (così come i valori predefiniti che variano dalla versione del sistema operativo) e non saranno necessariamente uguali su una macchina diversa.

È possibile impostare Larghezza e Altezza sull'elemento di contenuto della finestra (a <Grid> in questo caso), quindi impostare l'attributo SizeToContent di Window su WidthAndHeight. Questo ha le dimensioni iniziali della finestra esattamente dove voglio. Ma poi le cose non si ridimensionano più - Posso ridimensionare la finestra, ma il suo contenuto non viene ridimensionato con esso, perché ho specificato una dimensione fissa.

C'è un modo per impostare la dimensione iniziale del client di una finestra, preferibilmente senza code-behind? (Prenderò il code-behind se questo è l'unico modo, ma preferirei un approccio solo XAML se qualcuno ne ha uno.)

risposta

20

si può fare in code-behind al gestore di eventi Load in uno dei due modi:

NOTA: Il contenuto del LayoutRoot Grid è la stessa in entrambi gli esempi, ma la larghezza e L'altezza su LayoutRoot è specificata solo nell'esempio A.

A) ClearValue sul SizeToContent della della finestra e sul del contenuto di Larghezza e Altezza:

using System.Windows; 

namespace WpfWindowBorderTest 
{ 
    /// <summary> 
    /// Interaction logic for Window1.xaml 
    /// </summary> 
    public partial class Window1 : Window 
    { 
     public Window1() 
     { 
      InitializeComponent(); 
     } 

     private void Window_Loaded(object sender, RoutedEventArgs e) 
     { 
      ClearValue(SizeToContentProperty); 
      LayoutRoot.ClearValue(WidthProperty); 
      LayoutRoot.ClearValue(HeightProperty); 
     } 
    } 
} 

assumendo un layout di pagina come (notare l'impostazione SizeToContent e gestore di eventi Loaded sulla finestra e la larghezza e l'altezza specificata sulla LayoutRoot):

<Window x:Class="WpfWindowBorderTest.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="Window1" SizeToContent="WidthAndHeight" Loaded="Window_Loaded"> 
    <Grid x:Name="LayoutRoot" Width="300" Height="300" Background="Green"> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="1*"/> 
      <RowDefinition Height="3*"/> 
     </Grid.RowDefinitions> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="1*"/> 
      <ColumnDefinition Width="3*"/> 
     </Grid.ColumnDefinitions> 
     <Rectangle Grid.Row="0" Grid.Column="0" Fill="Black" /> 
     <Rectangle Grid.Row="0" Grid.Column="0" Width="75" Height="75" Fill="Red" /> 
     <Rectangle Grid.Row="1" Grid.Column="1" Fill="Yellow" /> 
     <Rectangle Grid.Row="1" Grid.Column="1" Width="225" Height="225" Fill="Red" /> 
    </Grid> 
</Window> 

o

B) l'impostazione della finestra Larghezza e Altezza contabilità per il sistema-specifica wi cliente ndow frame sizes:

utilizzando System.Windows;

namespace WpfWindowBorderTest 
{ 
    /// <summary> 
    /// Interaction logic for Window1.xaml 
    /// </summary> 
    public partial class Window1 : Window 
    { 
     public Window1() 
     { 
      InitializeComponent(); 

      const int snugContentWidth = 300; 
      const int snugContentHeight = 300; 

      var horizontalBorderHeight = SystemParameters.ResizeFrameHorizontalBorderHeight; 
      var verticalBorderWidth = SystemParameters.ResizeFrameVerticalBorderWidth; 
      var captionHeight = SystemParameters.CaptionHeight; 

      Width = snugContentWidth + 2 * verticalBorderWidth; 
      Height = snugContentHeight + captionHeight + 2 * horizontalBorderHeight; 
     } 
    } 
} 

assumendo un layout di pagina proporzionale come (nota n impostazione SizeToContent o gestore di eventi Loaded sulla finestra o larghezza e altezza specificato sul LayoutRoot):

<Window x:Class="WpfWindowBorderTest.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="Window1"> 
    <Grid x:Name="LayoutRoot" Background="Green"> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="1*"/> 
      <RowDefinition Height="3*"/> 
     </Grid.RowDefinitions> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="1*"/> 
      <ColumnDefinition Width="3*"/> 
     </Grid.ColumnDefinitions> 
     <Rectangle Grid.Row="0" Grid.Column="0" Fill="Black" /> 
     <Rectangle Grid.Row="0" Grid.Column="0" Width="75" Height="75" Fill="Red" /> 
     <Rectangle Grid.Row="1" Grid.Column="1" Fill="Yellow" /> 
     <Rectangle Grid.Row="1" Grid.Column="1" Width="225" Height="225" Fill="Red" /> 
    </Grid> 
</Window> 

non sono stato in grado di venire ancora con un modo per farlo in modo dichiarativo in XAML.

+1

Sono finalmente tornato a un progetto in cui avevo bisogno di questo, e la tua prima soluzione fa esattamente quello che voglio. Grazie! –

+0

L'opzione B qui funziona perfettamente per me. Esattamente quello che stavo cercando. – samuelesque

+0

L'opzione B apparentemente non funziona con Windows 7 (con tema aerodinamico di base). –

12

Puoi rimuovere gli attributi di larghezza e altezza della finestra in XAML e aggiungere SizeToContent = "Larghezza e altezza". Questo imposta le dimensioni iniziali della finestra sul suo contenuto, ma consente comunque di ridimensionarlo.

<Window x:Class="WpfApplication2.Window1" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="Window1" SizeToContent="WidthAndHeight"> 
    <Grid> 
     <TextBlock Text="How to set WPF window’s startup ClientSize?"/> 
    </Grid> 
</Window> 

Quando viene avviato, sembra che questo:

alt text http://img7.imageshack.us/img7/1285/onstart.png

ma è ancora possibile allungare con il mouse:

alt text http://img16.imageshack.us/img16/6687/stretched.png

2

faccio la seguente nel costruttore e aggiungi ResizeMode = "CanResizeWithGrip" in xaml, ma in genere dipende da quanto spazio occupa il tuo contenuto su st Artup

public Window1() 
{ 
    this.Height = SystemParameters.WorkArea.Height; 
    this.Width = SystemParameters.WorkArea.Width; 
} 
5

Trascorro un bel po 'di tempo per capire anche tutta la storia. È sorprendentemente difficile trovare una risposta XAML pura (zero-code dietro) a questa domanda in rete, quindi ecco la mia.

Quando progettiamo una finestra in Visual Studio WPF progettista, lo standard (e per impostazione predefinita) modo è quello di definire Width e Height proprietà sul Window, come questo in XAML:

<Window x:Class="WpfApplication1.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="75" Width="190"> 
    <Grid> 
     <Button Content="Right" HorizontalAlignment="Right" Margin="0,0,10,10" VerticalAlignment="Bottom" Width="75" /> 
     <Button Content="Left" HorizontalAlignment="Left" Margin="10,0,0,10" VerticalAlignment="Bottom" Width="75"/> 
    </Grid> 
</Window> 

Il progettista anteprima si presenta così:

enter image description here

tutto sembra fresco, ma quando si corre l'applicazione, a seconda della versione corrente di Windows, a tema e tutti di impostazioni di splay jazz, ci sono 99% di probabilità che la finestra di runtime sia non come quella progettata. Ecco come si presenta sul mio Windows 8.1:

enter image description here

La soluzione iniziale è, come nella risposta di Oren per utilizzare la proprietà SizeTocontent. Fondamentalmente dice a WPF di definire la dimensione della finestra dal suo contenuto (ovvero "dimensione del client"), invece della finestra stessa (ovvero "dimensione del client + tutto ciò che non è client/chrome/border roba totalmente incontrollabile").

Quindi, siamo in grado di definire il contenuto di essere di dimensione fissa, in questo modo:

<Window x:Class="WpfApplication1.MainWindowSizeToContentCentered" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" SizeToContent="WidthAndHeight"> 
    <Grid Height="40" Width="180"> 
     <Button Content="Right" HorizontalAlignment="Right" Margin="0,0,10,10" VerticalAlignment="Bottom" Width="75" /> 
     <Button Content="Left" HorizontalAlignment="Left" Margin="10,0,0,10" VerticalAlignment="Bottom" Width="75"/> 
    </Grid> 
</Window> 

E ora, la finestra di esecuzione appare esattamente come vogliamo (Nota altezza e la larghezza della griglia non hanno esattamente gli stessi valori della finestra originale - 40/180 vs 75/190 -, e va bene, come nella modalità di progettazione, è ora possibile solo dimenticare finestra Altezza e proprietà Width sempre):

enter image description here

Come si comporta quando viene ridimensionata la finestra?in questo modo, la griglia è centrata, che va bene se si vuole che il comportamento:

enter image description here

Ma, se vogliamo che il comportamento in questione, ("Posso ridimensionare la finestra, ma il suo contenuto doesn' . t ridimensionare con esso, perché ho specificato una dimensione fissa "), che era il comportamento originale troppo, invece di specificare larghezza e l'altezza, possiamo usare MinWidth e MinHeight, in questo modo:

sguardi finestra
<Window x:Class="WpfApplication1.MainWindowSizeToContentResizable" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" SizeToContent="WidthAndHeight"> 
    <Grid MinHeight="40" MinWidth="180"> 
     <Button Content="Right" HorizontalAlignment="Right" Margin="0,0,10,10" VerticalAlignment="Bottom" Width="75" /> 
     <Button Content="Left" HorizontalAlignment="Left" Margin="10,0,0,10" VerticalAlignment="Bottom" Width="75"/> 
    </Grid> 
</Window> 

il runtime lo stesso, ma l'esperienza di ridimensionamento è ora paragonabile al layout della finestra di default originale:

enter image description here

Questo dovrebbe essere il default WPF designer layout IMHO.

0

Simon Mourier messaggi una risposta eccellente, ma avevo bisogno della dimensione di un controllo per rinviare agli altri. Quindi l'inversione del comportamento di dimensionamento della finestra con l'attributo SizeToContent non era quello che mi serviva. Ho finito per seguire [Tim's][method to compute the non-client size] per sottrarre l'area non client dalla larghezza e altezza dinamica della finestra principale; in un elemento XAML <MultiBinding>. Ciò è stato ottenuto leggendo le proprietà SystemParameters.WindowCaptionHeight e SystemParameters.ResizeFramVerticalBorderWidth (vedere il codice IMultiValueConverter di seguito).

<Grid> 
    <Grid.RowDefinitions> 
    <RowDefinition x:Name="_mwR0" Height="Auto"/> 
    <RowDefinition x:Name="_mwR1" Height="4*"/> 
    <RowDefinition x:Name="_mwR2" Height="Auto"/> 
    <RowDefinition x:Name="_mwR3"> 
     <RowDefinition.Height> 
     <MultiBinding Converter="{StaticResource SizeToRemainderConverter}" Mode="TwoWay"> 
      <Binding ElementName="_LogWindow" Path="Height" Mode="TwoWay"/> 
      <Binding ElementName="_MainWindow" Path="Height" Mode="OneWay"/> 
      <Binding ElementName="_mwR0" Path="Height" Mode="OneWay"/> 
      <Binding ElementName="_mwR1" Path="Height" Mode="OneWay"/> 
      <Binding ElementName="_mwR2" Path="Height" Mode="OneWay"/> 
     </MultiBinding> 
     </RowDefinition.Height> 
    </RowDefinition> 
    </Grid.RowDefinitions> 
    <Menu IsMainMenu="True" Grid.Row="0">...</Menu> 
    <ListView Grid.Row="1">...</ListView> 
    <GridSplitter Grid.Row="2" ShowsPreview="True" HorizontalAlignment="Stretch" Height="6" VerticalAlignment="Center" Margin="0"/> 
    <RichTextBox x:Name="_LogWindow" Grid.Row="3"/> 
</Grid> 

_LogWindow è il controllo interno per l'ultima riga della griglia. Come la finestra principale viene ridimensionata, ho bisogno di ridurre questo controllo in ossequio agli altri.

Il convertitore è complicato dalla necessità di gestire entrambi i tipi di oggetto System.Double e System.Windows.GridLength. Conservo anche il layout tra le sessioni di applicazione, quindi avevo bisogno che il convertitore fosse bidirezionale (scuse per il codice denso).

public class SizeToRemainderConverter : IMultiValueConverter 
{ 
    public object Convert(object[] values, Type targetType, object parm, System.Globalization.CultureInfo culture) 
    { 
    double ret = 0.0; 
    if (values != null && values.Length > 0) 
    { 
     if (values[0].GetType().Name.Equals("String")) double.TryParse((values[0] as string), out ret); 
     else if (values[0].GetType().Name.Equals("GridLength")) ret = ((GridLength)values[0]).Value; 
     else ret = (double)System.Convert.ChangeType(values[0], typeof(double)); 
    } 

    double available = 0.0; 
    if (values != null && values.Length > 1) 
    { 
     if (values[1].GetType().Name.Equals("String")) double.TryParse((values[1] as string), out available); 
     else if (values[1].GetType().Name.Equals("GridLength")) available = ((GridLength)values[1]).Value; 
     else available = (double)System.Convert.ChangeType(values[1], typeof(double)); 

     available -= SystemParameters.WindowCaptionHeight; 
     available -= SystemParameters.ResizeFrameVerticalBorderWidth; 
     available -= SystemParameters.ResizeFrameVerticalBorderWidth; 
    } 

    for (int i = 2; i < (values?.Length ?? 0); ++i) 
    { 
     double delta = 0.0; 

     if (values[i].GetType().Name.Equals("String")) double.TryParse((values[i] as string), out delta); 
     else if (values[i].GetType().Name.Equals("GridLength")) delta = ((GridLength)values[i]).Value; 
     else delta = (double)System.Convert.ChangeType(values[i], typeof(double)); 
     available -= delta; 
    } 

    if (available < ret) ret = 0.0; 

    if (targetType.Name.Equals("GridLength")) return new GridLength(ret); 
    return System.Convert.ChangeType(ret, targetType); 
    } 

    public object[] ConvertBack(object v, Type[] t, object p, System.Globalization.CultureInfo c) 
    { 
    object[] ret = new object[t.Length]; 
    switch (v.GetType().Name) 
    { 
     case "Double": 
     for (int i = 0; i < t.Length; ++i) 
     { 
      if (t[i].Name.Equals("String")) ret[i] = v.ToString(); 
      else if (t[i].Name.Equals("GridLength")) ret[i] = new GridLength((v as double?) ?? 0.0); 
      else ret[i] = System.Convert.ChangeType(v, t[i]); 
     } 
     break; 

     case "GridLength": 
     GridLength gl = (v as GridLength?) ?? new GridLength(); 
     for (int i = 0; i < t.Length; ++i) 
     { 
      if (t[i].Name.Equals("String")) ret[i] = gl.Value.ToString(); 
      else if (t[i].Name.Equals("GridLength")) ret[i] = gl; 
      else ret[i] = System.Convert.ChangeType(gl.Value, t[i]); 
     } 
     break; 

     case "String": 
     default: 
     double d = 0.0; 
     double.TryParse(v as string, out d); 
     for (int i = 0; i < t.Length; ++i) 
     { 
      if (t[i].Name.Equals("String")) ret[i] = v.ToString(); 
      else if (t[i].Name.Equals("GridLength")) ret[i] = new GridLength(d); 
      else ret[i] = System.Convert.ChangeType(v, t[i]); 
     } 
     break; 
    } 

    return ret; 
    } 
} 
Problemi correlati