2009-11-08 9 views
35

Ho un Grid all'interno di una Canvas definita in questo modo:Perché in questo caso ActualWidth e ActualHeight 0.0?

<Canvas x:Name="outerCanvas"> 
    <Grid Grid.Row="1" Name="cGrid" ShowGridLines="True" Width="{Binding Path=ActualWidth, RelativeSource={RelativeSource AncestorType={x:Type Canvas}}}" Height="{Binding Path=ActualHeight, RelativeSource={RelativeSource AncestorType={x:Type Canvas}}}"> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition /> 
      <ColumnDefinition/> 
      <ColumnDefinition/> 
     </Grid.ColumnDefinitions> 
     <Grid.RowDefinitions> 
      <RowDefinition /> 
      <RowDefinition /> 
     </Grid.RowDefinitions> 
     <Rectangle Name="rectangle1" Stroke="Black" Fill="AntiqueWhite" /> 
     <Rectangle Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="1" Grid.RowSpan="1" Name="rectangle2" Stroke="Black" Fill="AliceBlue" /> 
     <Rectangle Grid.Row="0" Grid.Column="2" Grid.ColumnSpan="1" Grid.RowSpan="1" Name="rectangle3" Stroke="Black" Fill="Aqua" /> 
     <Rectangle Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" Grid.RowSpan="1" Name="rectangle4" Stroke="Black" Fill="DarkViolet" /> 
    </Grid> 
</Canvas> 

mio problema è che, sulla costruzione della finestra, dopo InitializeComponents() sia Grid.ColumnDefinitions[0].ActualWidth o "qualsiasi rettangolo di". ActualWidth sono tutti impostati su 0.0 (lo stesso per altezze). Non sto cercando di capire cosa fare per ottenere queste informazioni. qualsiasi aiuto?

Osservazioni:

  1. Non sto definig la larghezza e l'altezza di tela esterna, ma se lo faccio, does't risolvere il mio problema.
  2. Al runtime posso vedere che questo Canvas/Grid occupa l'intero spazio della finestra, in modo che ogni rettangolo interno ha ActualWidth s e ActualHeight s
  3. larghezza/altezza della griglia è legata alla tela ma provato a rimuovere questa associazione e il problema persistente

risposta

69

ActualHeight e ActualWidth non sono impostati finché il controllo non viene misurato e organizzato. Di solito non c'è nulla in InitializeComponent() che causa una misura, quindi quando ritorna questi saranno ancora zero.

È possibile forzare questi in modo che vengano calcolati in precedenza semplicemente chiamando i metodi della finestra Measure() e Arrange() manualmente dopo il ritorno della finestra InitializeComponent().

Se si dimensionamento al contenuto:

window.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); 
window.Arrange(new Rect(0, 0, window.DesiredSize.Width, window.DesiredSize.Height)); 

Se si utilizza una dimensione della finestra esplicito:

window.Measure(new Size(Width, Height)); 
window.Arrange(new Rect(0, 0, window.DesiredSize.Width, window.DesiredSize.Height)); 
+1

Grazie! Solo una piccola correzione: window.Misure restituisce nulla. Cambia le proprietà DesiredWidth/DesiredHeight :) Ma la tua idea è giusta. –

+1

Ecco cosa succede quando digiti il ​​codice dalla testa senza ricontrollare le API. Grazie per la correzione. MeasureOverride restituisce la dimensione, ma Misura solo li memorizza. Risposta corretta –

+11

Non sono sicuro che "DesiredWidth" abbia funzionato prima, ma le versioni più recenti di .NET utilizzano DesiredSize.Width e DesiredSize.Altezza –

52

Ray è corretta (+1) che questo è dovuto al fatto che la misurare e organizzare il passaggio non è ancora stato eseguito. Tuttavia, piuttosto che forzare un altro passaggio di layout (costoso), si può solo aspettare fino a quando il controllo è stato caricato prima di accedere ai ActualXxx proprietà:

public MyWindow() 
{ 
    Loaded += delegate 
    { 
     // access ActualWidth and ActualHeight here 
    }; 

} 
+2

Accetto. Waiting for Loaded è l'approccio migliore IMHO. –

+0

Grazie! Solo curioso ... Perché non c'è un metodo OnLoaded su Window? –

+3

In attesa di caricamento è una buona idea (+1) e funzionerà nella maggior parte dei casi. Nota che quando non ti connetti mai a una PresentationSource (cioè non mostri mai la finestra), Loaded non verrà mai chiamato. Mi sono imbattuto in questo prima, ad esempio quando decidevo se includere o meno un controllo su una pagina. Quindi direi che usare Loaded è migliore quando è possibile e copre tutti i casi, altrimenti usare Measure/Arrange è meglio. Detto questo, nel 90% dei casi le migliori pratiche saranno di stare lontano da ActualWidth/ActualHeight completamente. (ad esempio, più/beter pannelli, associazione all'altezza/larghezza, MeasureOverride) –

-7

ActualWidth e ActualHeight sono disponibili solo dopo XAML carico completato, prima di caricare come si può trova questi parametri?

Utilizzare l'evento Loaded e al suo interno individuare ActualWidth e ActualHeight.

private void me_Loaded(object sender, RoutedEventArgs e) 
{ 
    // do your stuffs here. 
} 
+6

quella era la risposta sopra da Kent – kenny

+0

il concetto è lo stesso non risponde –

-1

Nel nostro caso la soluzione è stata semplice, come tutti dicevano ActualWidth e ActualHeight necessari per ottenere chiamato dopo l'Loaded ancora completa, Così abbiamo appena avvolto il codice in un dispatcher e impostare la priorità alla caricati come di seguito:

Dispatcher.Invoke(new Action(() => 
{ 
    graphHeight = ActualHeight; 
    graphWidth = ActualWidth; 
}), DispatcherPriority.Loaded); 
Problemi correlati