Как настроить сетку в качестве шаблона для элемента управления Items?

Я пытаюсь создать ItemsControl, который использует сетку в качестве своего ItemsPanel таким образом, чтобы он имел два столбца, где ширина первого столбца - это ширина самого широкого элемента в этом столбце, а также строки, необходимые для отображения всех предметы

По сути, я хочу следующее, но как-то внутри ItemsControl, чтобы я мог привязываться к коллекции объектов:

<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> 

Изменить: ответ Рэйчел отлично сработал, вот рабочий пример.

(Я переместил Grid.IsSharedSizeScope="True" в ItemsPanel, не уверенный, что Рэйчел хотела поместить его в ItemTemplate (что не сработало))

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>

person pastillman    schedule 16.05.2013    source источник
comment
Я не уверен, как это будет работать, поскольку элемент в моем примере содержит как заголовок, так и содержимое.   -  person pastillman    schedule 17.05.2013
comment
используй свое воображение, чувак. В противном случае дайте мне час или около того, чтобы закончить мою работу здесь, и я могу создать пример для вас.   -  person Federico Berasategui    schedule 17.05.2013
comment
Комментирование вашего рабочего примера; настройка ItemsPanelTemplate не требуется, так как StackPanel в любом случае является значением по умолчанию. Вы можете немного упростить свое решение, установив Grid.IsSharedSizeScope="True" непосредственно в ItemsControl.   -  person kwitee    schedule 20.06.2019


Ответы (2)


Здесь есть несколько проблем для ItemsControl:

  • Получение вашего первого столбца, соответствующего ширине самого большого элемента
  • Генерация динамического количества строк
  • Создание более одного элемента для каждой итерации ItemsControl

Последнее является действительно самой большой проблемой, потому что ItemsControl оборачивает каждый ItemTemplate в ContentPresenter, поэтому по умолчанию нет способа создать более одного элемента на панели для каждой итерации ItemsControl. Ваш конечный результат будет выглядеть так:

<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> 

Мое лучшее предложение — создать ItemTemplate, который содержит 1x2 Grid, и использовать Grid.IsSharedSizeScope, чтобы сделать ширину первого столбца общей. (ItemsPanelTemplate останется по умолчанию StackPanel.)

Таким образом, конечный результат будет выглядеть так:

<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> 
person Rachel    schedule 17.05.2013
comment
Обратите внимание, что Grid.IsSharedScope="True" следует устанавливать в родительском контейнере, не в дочерних сетках. Этот (в остальном очень хороший и полезный) ответ оставил меня в замешательстве с этим свойством IsSharedScope. - person ForNeVeR; 26.01.2017

Вы можете использовать ListView

<ListView ItemsSource="{Binding MyList}">
    <ListView.View>
        <GridView>
            <GridView.ColumnHeaderContainerStyle>
                <Style TargetType="{x:Type GridViewColumnHeader}">
                    <Setter Property="Visibility" Value="Collapsed" />
                </Style>
            </GridView.ColumnHeaderContainerStyle>
            <GridViewColumn 
                Header="" 
                Width="Auto" 
                DisplayMemberBinding="{Binding Header}"/>
            <GridViewColumn 
                Header="" 
                DisplayMemberBinding="{Binding Value}"/>
        </GridView>
    </ListView.View>
</ListView>

ColumnHeaderContainerStyle скрывает GridViewHeader

person Smotsch    schedule 17.05.2013
comment
Спасибо, но мне действительно не нужны ползунки столбцов или выбор, присутствующий в списке. - person pastillman; 18.05.2013