ItemsControlの派生クラスでいろいろ調べた。
ItemsControlはおおむねこんな動きをしているのだろう。(簡単のため、ResourceDictionaryなどは無視している)
Size MeasureOverride(Size availableSize) { ItemsPresenter presenter = 【ビジュアルツリーからItemsPresenterを取得】; Panel panel = this.ItemsPanel; if (panel == null) { panel = new StackPanel(); } 【presenterにpanelを追加】; foreach(object item in this.ItemsSource) { if (this.IsItemItsOwnContainerOverride(item)) { panel.Children.Add(item); } else { DependencyObject element = this.GetContainerForItemOverride(); this.PrepareContainerForItemOverride(element, item); panel.Children.Add(element); } } 【ビジュアルツリーの子要素】.Measure(); return 【ビジュアルツリーの子要素】.DesirableSize; } DependencyObject GetContainerForItemOverride() { return new ContentPresenter(); } void PrepareContainerForItemOverride(element, item) { ContentPresenter presenter = element as ContentPresenter; if (presenter != null) { presenter.ContentTemplate = this.ItemTemplate; presenter.Content = item; } }
そして、ContentPresenterはおおむねこんな動きをしているのだろう。
Size MeasureOverride(Size availableSize) { if (this.ContentTemplate != null) { DependencyObject content = this.ContentTemplate.LoadContent(); FrameworkElement element = content as FrameworkElement; if (element != null) { element.DataContext = this.Content; element.Measure(); return element.DesirableSize; } } }
とあるカスタムコントロールを作りたいのだが、やりたいことを実現するにはContentPresenterのMeasureを呼ぶ前にContentTemplate.LoadContentを呼び出しておかないといけないようだ。PrepareContainerForItemOverrideあたりでLoadContentを呼び出して、結果は使い捨てようかな。
(追記)ContentTemplate.LoadContentでButtonを取得したんだけど、Measureの結果が(0, 0)。何が足りない?