2009-11-08 9 views
35

Tengo un Grid dentro de un Canvas define así:¿Por qué son ActualWidth y ActualHeight 0.0 en este caso?

<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> 

Mi problema es que, en el constructor de la ventana, después de InitializeComponents() ya sea Grid.ColumnDefinitions[0].ActualWidth o "cualquier rectángulo". ActualWidth están todos configurados en 0.0 (lo mismo para las alturas). No estoy averiguando qué hacer para obtener esta información. ¿alguna ayuda?

Observaciones:

  1. No estoy definig la anchura y la altura de la lona exterior, pero si lo hago, es does't resolver mi problema.
  2. En tiempo de ejecución puedo ver que este Canvas/Grid ocupa todo el espacio de la ventana, por lo que cada rectángulo interior tiene ActualWidth s y ActualHeight s
  3. de la rejilla de anchura/altura se une a la lona pero he intentado retirar esta unión y mi problema persistieron

Respuesta

69

ActualHeight y ActualWidth no se ajustan hasta que se mide y dispuesto el control. Por lo general, no hay nada en InitializeComponent() que cause una medida, por lo tanto, cuando vuelva, seguirá siendo cero.

Puede forzar que se calculen antes simplemente llamando a los métodos Measure() y Arrange() de la ventana manualmente después de que InitializeComponent() devuelve la ventana.

Si está de tamaño para contenido:

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

Si está usando un tamaño de ventana explícita:

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

Gracias! Solo una pequeña corrección: window.Measure devuelve void. Cambia las propiedades DesiredWidth/DesiredHeight :) Pero tu idea es correcta. –

+1

Eso es lo que sucede cuando escribe el código en la parte superior de la cabeza sin verificar dos veces las API. Gracias por la corrección. MeasureOverride devuelve el tamaño, pero Measure simplemente los almacena. Respuesta corregida –

+11

No estoy seguro de si "DesiredWidth" funcionó antes, pero las versiones más nuevas de .NET usan DesiredSize.Width y DesiredSize.Altura –

52

Ray es correcto (1) que esto se debe al hecho de que la medir y organizar el pase aún no se ha ejecutado. Sin embargo, en lugar de obligar a otro pase diseño (caro), puede simplemente esperar hasta que su control haya cargado antes de acceder a los ActualXxx propiedades:

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

} 
+2

De acuerdo. Waiting for Loaded es el mejor enfoque en mi humilde opinión. –

+0

Gracias! Simplemente curioso ... ¿Por qué no hay un método OnLoaded en la ventana? –

+3

Waiting for Loaded es una buena idea (+1) y funcionará en la mayoría de los casos. Pero tenga en cuenta que cuando nunca se conecta a PresentationSource (es decir, nunca se muestra la ventana), nunca se llamará a Loaded. Me he encontrado con esto antes, por ejemplo, al decidir si incluir o no un control en una página. Así que yo diría que usar Loaded es mejor cuando es posible y cubre todos los casos; de lo contrario, usar Measure/Arrange es mejor. Dicho esto, en el 90% de los casos, la mejor práctica será mantenerse alejado de ActualWidth/ActualHeight por completo. (p. ej., paneles más/borrosos, encuadernación en altura/ancho, MeasureOverride) –

-7

ActualWidth y ActualHeight están disponibles sólo después de XAML carga completada, antes de cargar ¿cómo se puede encontrar estos parámetros?

Utilice el evento Cargado y dentro de él encontrará ActualWidth y ActualHeight.

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

esa fue la respuesta anterior del concepto Kent – kenny

+0

es lo mismo que no responder –

-1

En nuestro caso, la solución era simple, como todo el mundo dice ActualWidth y ActualHeight necesitaban ser llamado después de la cargada incluso completa, Así que acaba de terminar el código en un despachador y establecer la prioridad de carga como a continuación:

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