Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to setup a grid as template for an Items control?

Tags:

I'm trying to create an ItemsControl that uses a grid as its ItemsPanel in such a way that it has two columns, where the first columns width is the width of the widest item in that column, and has as may rows needed to display all the items

Basically, I want the following, but somehow within an ItemsControl so that I can bind to a collection of objects:

<Grid>         <Grid.ColumnDefinitions>             <ColumnDefinition Width="auto"/>             <ColumnDefinition Width="*"/>         </Grid.ColumnDefinitions>          <Grid.RowDefinitions>             <RowDefinition Height="auto"/>             <RowDefinition Height="auto"/>             <RowDefinition Height="auto"/>         </Grid.RowDefinitions>          <Label Content="{Binding Items[0].Header}"/>         <TextBox Text="{Binding Items[0].Content}" Grid.Column="1"/>          <Label Content="{Binding Items[1].Header}" Grid.Row="1"/>         <TextBox Text="{Binding Items[1].Content}" Grid.Row="1" Grid.Column="1"/>          <Label Content="{Binding Items[2].Header}" Grid.Row="2"/>         <TextBox Text="{Binding Items[2].Content}" Grid.Row="2" Grid.Column="1"/>     </Grid>  

Edit : Rachels answer worked great, here is a working example.

(I moved the Grid.IsSharedSizeScope="True" to the ItemsPanel, not sure if Rachel meant to put it in the ItemTemplate (which didn't work))

namespace WpfApplication23 {     public partial class Window1 : Window     {         public List<Item> Items { get; set; }          public Window1()         {             Items = new List<Item>()              {                  new Item(){ Header="Item0", Content="someVal" },                 new Item(){ Header="Item1", Content="someVal" },                 new Item(){ Header="Item267676", Content="someVal" },                 new Item(){ Header="a", Content="someVal" },                 new Item(){ Header="bbbbbbbbbbbbbbbbbbbbbbbbbb", Content="someVal" },                 new Item(){ Header="ccccccc", Content="someVal" }              };              InitializeComponent();              DataContext = this;         }     }      public class Item     {         public string Header { get; set; }         public string Content { get; set; }     } }  <Window x:Class="WpfApplication23.Window1"         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">      <ItemsControl ItemsSource="{Binding Items}">          <ItemsControl.ItemsPanel>             <ItemsPanelTemplate>                 <StackPanel Grid.IsSharedSizeScope="True"/>             </ItemsPanelTemplate>         </ItemsControl.ItemsPanel>          <ItemsControl.ItemTemplate>             <DataTemplate>                 <Grid>                     <Grid.ColumnDefinitions>                         <ColumnDefinition SharedSizeGroup="ColumnOne" />                         <ColumnDefinition Width="*" />                     </Grid.ColumnDefinitions>                     <Label Content="{Binding Header}"/>                     <TextBox Text="{Binding Content}" Grid.Column="1"/>                 </Grid>             </DataTemplate>         </ItemsControl.ItemTemplate>     </ItemsControl> </Window> 
like image 916
pastillman Avatar asked May 16 '13 20:05

pastillman


People also ask

What is ItemsPanelTemplate?

The ItemsPanelTemplate specifies the panel that is used for the layout of items. GroupStyle has a Panel property that is of type ItemsPanelTemplate. ItemsControl types have an ItemsPanel property that is of type ItemsPanelTemplate. Each ItemsControl type has a default ItemsPanelTemplate.

How do you use item control?

Use either the Items or the ItemsSource property to specify the collection to use to generate the content of your ItemsControl. You can set the ItemsSource property to any type that implements IEnumerable. ItemsSource is typically used to display a data collection or to bind an ItemsControl to a collection object.


1 Answers

There are multiple problems here for an ItemsControl:

  • Getting your first column to match the width of the largest item
  • Generating a dynamic number of rows
  • Generating more than one item for each iteration of the ItemsControl

The last one is really the biggest problem, because an ItemsControl wraps each ItemTemplate in a ContentPresenter, so there is no default way of creating more than one item in the panel for each Iteration of the ItemsControl. Your end result would look like this:

<Grid>     ...      <ContentPresenter>         <Label Content="{Binding Items[0].Header}"/>         <TextBox Text="{Binding Items[0].Content}" Grid.Column="1"/>     </ContentPresenter>     <ContentPresenter>         <Label Content="{Binding Items[1].Header}" Grid.Row="1"/>         <TextBox Text="{Binding Items[1].Content}" Grid.Row="1" Grid.Column="1"/>     </ContentPresenter>     <ContentPresenter>         <Label Content="{Binding Items[2].Header}" Grid.Row="2"/>         <TextBox Text="{Binding Items[2].Content}" Grid.Row="2" Grid.Column="1"/>     </ContentPresenter> </Grid>  

My best suggestion would be to create an ItemTemplate that contains a 1x2 Grid, and use Grid.IsSharedSizeScope to make the width of the first column shared. (The ItemsPanelTemplate would remain the default StackPanel.)

This way, the end result would look like this:

<StackPanel>     <ContentPresenter>         <Grid IsSharedSizeScope="True">             <Grid.ColumnDefinitions>                 <ColumnDefinition SharedSizeGroup="ColumnOne" />                 <ColumnDefinition Width="*" />             </Grid.ColumnDefinitions>             <Label Content="{Binding Header}"/>             <TextBox Text="{Binding Content}" Grid.Column="1"/>         </Grid>     </ContentPresenter>     <ContentPresenter>         <Grid IsSharedSizeScope="True">             <Grid.ColumnDefinitions>                 <ColumnDefinition SharedSizeGroup="ColumnOne" />                 <ColumnDefinition Width="*" />             </Grid.ColumnDefinitions>             <Label Content="{Binding Header}"/>             <TextBox Text="{Binding Content}" Grid.Column="1"/>         </Grid>     </ContentPresenter>     ... </StackPanel>  
like image 126
Rachel Avatar answered Sep 20 '22 08:09

Rachel