web-dev-qa-db-fra.com

Pourquoi ActualWidth et ActualHeight 0.0 dans ce cas?

J'ai un Grid à l'intérieur d'un Canvas défini comme ceci:

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

Mon problème est que, sur le constructeur Window, après InitializeComponents() soit Grid.ColumnDefinitions[0].ActualWidth Soit "tout rectangle" .ActualWidth sont tous définis sur 0.0 (le même pour les hauteurs). Je ne sais pas quoi faire pour obtenir ces informations. De l'aide?

Observations:

  1. Je ne définis pas la largeur et la hauteur de la toile extérieure, mais si je le fais, cela ne résout pas mon problème.
  2. Au moment de l'exécution, je peux voir que ce Canvas/Grid Occupe tout l'espace de la fenêtre, donc chaque rectangle à l'intérieur contient ActualWidths et ActualHeights
  3. La largeur/hauteur de la grille est liée à la toile mais j'ai essayé de supprimer cette liaison et mon problème persiste.
41
André Pena

ActualHeight et ActualWidth ne sont pas définis tant que le contrôle n'est pas mesuré et arrangé. Habituellement, il n'y a rien dans InitializeComponent() qui provoque une mesure, donc quand elle retourne, elles seront toujours nulles.

Vous pouvez forcer ces derniers à être calculés plus tôt en appelant simplement les méthodes Measure() et Arrange() de la fenêtre manuellement après le retour de la fenêtre InitializeComponent().

Si vous dimensionnez en fonction du contenu:

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

Si vous utilisez une taille de fenêtre explicite:

window.Measure(new Size(Width, Height));
window.Arrange(new Rect(0, 0, window.DesiredSize.Width, window.DesiredSize.Height));
76
Ray Burns

Ray a raison (+1) que cela est dû au fait que la mesure et l'arrangement n'ont pas encore été exécutés. Cependant, plutôt que de forcer une autre passe de mise en page (coûteuse), vous pouvez simplement attendre que votre contrôle soit chargé avant d'accéder aux propriétés ActualXxx:

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

}
62
Kent Boogaart

Dans notre cas, la solution était simple, comme tout le monde a dit que ActualWidth et ActualHeight devaient être appelés après la fin de Loaded, nous avons donc simplement enveloppé le code dans un répartiteur et défini la priorité sur Loaded comme ci-dessous:

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