Stretching controls to fill ItemsControl

社会主义新天地 提交于 2019-11-29 01:11:26

Replace the item control's panel with a UniformGrid, this will size all children so everything fits exactly:

<ItemsControl>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <UniformGrid Rows="1"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>
Gregyski

I was able to build on Nir's answer to fulfill my optional criterion allowing for WPF-managed stretching with multiple rows.

First you must be able to alter the properties of the template UniformGrid. To do that you need to store a reference to it. There are multiple methods for accomplishing this. I chose to handle the Loaded event for the UniformGrid and store a reference at that time.

<ItemsControl ItemsSource="{Binding}">
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <UniformGrid Rows="1" Loaded="UniformGrid_Loaded" />
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>
</ItemsControl>

And in the code behind:

UniformGrid uniformgridButtons;
private void UniformGrid_Loaded(object sender, RoutedEventArgs e)
{
  uniformgridButtons = sender as UniformGrid;
}

Then, handle the SizeChanged event and adjust the rows parameter according to whatever criteria you wish.

private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
  if ((uniformgridButtons != null) && (this.Width > 0))
  {
    // Set row count according to your requirements
    uniformgridButtons.Rows = (int)(1 + ((this.MinWidth * iButtonCount) / this.Width));
  }
}

So this allows WPF to manage the stretching like in Nir's answer, but allows you to explicitly adjust the number of rows. The above code gives this result:

(Animated sample here)


Update 2009/08/28:

I was adjusting my learning application so that the ItemsControl was in a DataTemplate in a separate ResourceDictionary. However, events such as Loaded cannot be handled in an external ResourceDictionary XAML file because it has no code-behind (usually). Therefore, I needed to cache the reference to the UniformGrid using a different technique.

I instead used Alan Haigh's FindItemsPanel method (10th reply). First, I replaced the ItemsControl with :

<ContentPresenter x:Name="contentpresenterButtons" Content="{Binding obscolButtons}" />

Then in my ResourceDictionary, I put the ItemsControl in the DataTemplate:

<DataTemplate DataType="{x:Type local:Buttons}">
  <ItemsControl ... 
</DataTemplate>

Finally, I stored the reference to the templated UniformGrid as so:

private void Window_Loaded(object sender, RoutedEventArgs e) {
  uniformgridButtons = FindItemsPanel<UniformGrid>(contentpresenterButtons);
  // Also call the code in Window_SizeChanged which I put in another method
}

This works just the same as my previous solution but without requiring an event handler in the ResourceDictionary.

<!-- width must be explicitly set for this example -->
<StackPanel 
    Name="MyStack" 
    Orientation="Horizontal"
    Width="250"
    Load="Window_Loaded"> 
    <Button/>
    <Button/>
    <Button/>
</StackPanel>

public void Window_Loaded(object sender, RoutedEventArgs e)
{
    UIElementCollection elements = MyStack.Children;
    int count = elements.Count;

    foreach (UIElement element in elements)
    {
        if (element is Button)
            ((Button)element).Width = MyStack.Width / count;
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!