2009-11-08 2 views
35

У меня есть Grid внутри Canvas, определенной следующим образом:Почему в этом случае значение ActualWidth и 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> 

Моя проблема заключается в том, что на конструкторе окна, после InitializeComponents() либо Grid.ColumnDefinitions[0].ActualWidth или «любой прямоугольник». ActualWidth установлены на 0.0 (то же самое для высот). Я не понимаю, что делать, чтобы получить эту информацию. любая помощь?

Наблюдение:

  1. Я не definig внешней ширины холста и высоту, но если я делаю, это does't решить мою проблему.
  2. Во время выполнения я могу видеть, что это Canvas/Grid занимает весь пространство окна, так что каждый прямоугольник внутри него есть ActualWidth с и ActualHeight сек
  3. Сетка в ширина/высота привязана к холсту, но я попытался удалить эту привязку и мою проблему сохраняются

ответ

69

ActualHeight и ActualWidth не установлены до тех пор, пока контроль не будет измерен и не будет установлен. Обычно в InitializeComponent() ничего не происходит, что вызывает меру, поэтому при ее возврате они все равно будут равны нулю.

Вы можете заставить их быть вычисленными ранее, просто вызвав методы окна Measure() и Arrange() вручную после возвращения окна InitializeComponent().

Если вы проклейки к содержанию:

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

Если вы используете явный размер окна:

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

Спасибо! Просто небольшая коррекция: window.Measure возвращает void. Он изменяет свойства DesiredWidth/DesiredHeight :) Но ваша идея правильная. –

+1

Это то, что происходит, когда вы вводите код с верхней части головы без двойной проверки API. Спасибо за исправление. MeasureOverride возвращает размер, но Measure просто сохраняет их. Ответ исправлен. –

+11

Не уверен, что раньше работал «DesiredWidth», но более новые версии .NET используют DesiredSize.Width и DesiredSize.Высота –

52

Ray является правильным (+1), что это связано с тем, что мера и организовать проход еще не исполнен. Тем не менее, а не заставлять другой проход макета (дорогой), вы можете просто подождать, пока ваш контроль не загружен до получения доступа к ActualXxx свойства:

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

} 
+2

Согласен. Ожидание загрузки - лучший подход ИМХО. –

+0

Спасибо! Просто любопытно ... Почему нет метода OnLoaded в окне? –

+3

Ожидание загрузки - хорошая идея (+1) и будет работать в большинстве случаев. Но обратите внимание, что когда вы никогда не подключаетесь к PresentationSource (то есть никогда не показываете окно), Loaded никогда не будет вызываться. Я столкнулся с этим раньше, например, при принятии решения о включении элемента управления на страницу. Поэтому я бы сказал, что использование Loaded лучше, когда это возможно, и охватывает все случаи, в противном случае лучше использовать Measure/Arrange. Тем не менее, в 90% случаев лучше всего избегать ActualWidth/ActualHeight. (например, больше/beter панели, привязка к высоте/ширине, MeasureOverride) –

-7

ActualWidth и ActualHeight доступны только после того, как XAML загрузка завершена, перед загрузкой как вы можете найти эти параметры?

Использование Загружено событие и внутри него найти ActualWidth и ActualHeight.

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

это был ответ выше от Kent – kenny

+0

концепция такое же не ответ –

-1

В нашем случае решение было простым, как все сказал ActualWidth и ActualHeight нужно дозвонились после Loaded даже завершает, Таким образом, мы просто обернуты код в диспетчеру и установить приоритет Loaded, как показано ниже:

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