Reputation: 59336
I have a Grid
inside a Canvas
defined like this:
<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>
My problem is that, on the Window constructor, after InitializeComponents()
either Grid.ColumnDefinitions[0].ActualWidth
or "any rectangle".ActualWidth
are all set to 0.0 (the same for heights). I'm not figuring out what to do to get this information. Any help?
Observations:
Canvas/Grid
occupies the entire window space, so every rectangle inside it has ActualWidth
s and ActualHeight
sUpvotes: 49
Views: 70239
Reputation: 62919
ActualHeight
and ActualWidth
are not set until the control is measured and arranged. Usually there is nothing in InitializeComponent()
that causes a measure, so when it returns these will still be zero.
You can force these to be computed earlier by simply calling the window's Measure()
and Arrange()
methods manually after the window's InitializeComponent()
returns.
If you are sizing to content:
window.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
window.Arrange(new Rect(0, 0, window.DesiredSize.Width, window.DesiredSize.Height));
If you are using an explicit window size:
window.Measure(new Size(Width, Height));
window.Arrange(new Rect(0, 0, window.DesiredSize.Width, window.DesiredSize.Height));
Upvotes: 85
Reputation: 635
In our case the solution was simple, as everybody said ActualWidth and ActualHeight needed to get called after the Loaded even completes, So we just wrapped the code in a dispatcher and set the priority to Loaded as below:
Dispatcher.Invoke(new Action(() =>
{
graphHeight = ActualHeight;
graphWidth = ActualWidth;
}), DispatcherPriority.Loaded);
Upvotes: 3
Reputation: 178660
Ray is correct (+1) that this is due to the fact that the measure and arrange pass has not executed yet. However, rather than force another layout pass (expensive), you can just wait until your control has loaded before accessing the ActualXxx
properties:
public MyWindow()
{
Loaded += delegate
{
// access ActualWidth and ActualHeight here
};
}
Upvotes: 73