ItemsControl только с пользовательскими субэлементами - PullRequest
0 голосов
/ 13 марта 2012

Я хотел бы создать пользовательский компонент, который размещает свои дочерние элементы либо в StackPanel, либо в Grid (с переменным числом строк, что заставляет меня рассмотреть вместо StackPanel).Элементы - это пользовательские элементы / объекты, которые просто содержат некоторую конфигурацию, на основе которой создается несколько элементов управления для их отображения (некоторые надписи и текстовые поля).

В идеале компонент должен использоваться как-то так (гдеSpecializedCustomPanelItem - это подтип CustomPanelItem):

<CustomPanel>
    <CustomPanelItem Param1="value A" Param2="value B">Text</CustomPanelItem>
    <CustomPanelItem Param1="value C">Other text</CustomPanelItem>
    <SpecializedCustomPanelItem>More text</SpecializedCustomPanelItem>
    <!-- The number of items is variable -->
</CustomPanel>

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

Однако я бы хотел, чтобы элементы внутри этого ItemsControl были определенного типа (т.е. CustomPanelItem или подтип).Я на самом деле думал, что ItemsControl позволит это, так же как и вы внутри ComboBox или MenuItem, но получается, что он на самом деле допускает любой подтип и, если необходимо, оборачивает их в контейнер для предметов.

Так что я подумал, действительно ли ItemsControl - это то, что я ищу, так как я не хочу никаких «причудливых» вещей, таких как выделение или прокрутка, которые реализует большинство этих элементов управления.Я на самом деле хочу только создать простой интерфейс с общим шаблоном в приложении, которое автоматически генерирует эти компоненты и размещает их в Grid / StackPanel.

Должен ли я по-прежнему использовать ItemsControl илиСкорее построить еще один пользовательский компонент?

Ответы [ 2 ]

4 голосов
/ 13 марта 2012

В этом случае вам не нужен пользовательский компонент.Изменение типа ItemsPanel на любой тип, который вам нужен + несколько шаблонов для элементов должны помочь.

Однако, чтобы ответить на вопрос в заголовке: Если вы хотите, чтобы элемент управления элементами принимал только определенный типпредметы, вам нужно будет создать

a.CustomItemsControlб.CustomItemsControlItem

Затем для CustomItemsControl вы должны объявить атрибут

[StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(CustomItemsControlItem))]

. Затем вам также нужно будет

    protected override DependencyObject GetContainerForItemOverride()
    {
        return new CustomItemsControlItem(); 
        // You can throw an exception here
    }

    protected override bool IsItemItsOwnContainerOverride(object item)
    {
        return item is CustomItemsControlItem;
    }

Если память служит, это должно вынудить ItemsControl кне допускайте добавления других типов в качестве дочерних и должны вызывать исключения.Затем вы могли бы сделать некоторую магию внутри CustomItemsControlItem, определив некоторые свойства DependencyProperties, которые затем можно установить при добавлении элементов в XAML.

Но все же, если у вас есть несколько типов в вашей ViewModel, которые вы хотите правильно отобразить, все равно правильным способом будет предоставить несколько шаблонов для CustomItemsControlItem, нацеленных на ваши типы ViewModel.

Надеюсь, это поможет.

1 голос
/ 13 марта 2012

Это звучит идеально для ItemsControl

. Вы можете установить ItemsPanelTemplate, чтобы определить тип панели, в которой будут храниться ваши элементы, и установить ItemContainerTemplate, чтобы определить, как рисовать каждый элемент.

Если элементы должны отображаться по-разному в зависимости от их типа, я бы предложил использовать неявные шаблоны данных вместо установки ItemContainerTemplate

<Window.Resources>
    <DataTemplate DataType="{x:Type my:BasePanelItem}">
        <my:CustomPanelItem Param1="{Binding Param1}" Param2="{Binding Param2}" Content="{Binding SomeValue}" />
    </DataTemplate>
    <DataTemplate DataType="{x:Type my:SpecializedPanelItem}">
        <my:SpecializedCustomPanelItem Content="{Binding SomeValue}" />
    </DataTemplate>
</Window.Resources>


<ItemsControl ItemsSource="{Binding MyItems}">
    <!-- ItemsPanelTemplate -->
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <my:CustomPanel />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

Вы упомянули, что, возможно, хотите использоватьдинамически создаваемая Grid вместо StackPanel.Если вы это сделаете, вас могут заинтересовать некоторые GridHelpers , которые я разместил в своем блоге.Это позволит вам связать количество столбцов / строк на Grid в ItemsPanelTemplate

<ItemsControl ItemsSource="{Binding MyCollection}">
    <!-- ItemsPanelTemplate -->
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Grid local:GridHelpers.RowCount="{Binding RowCount}"
                  local:GridHelpers.ColumnCount="{Binding ColumnCount}" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>

    <!-- ItemContainerStyle -->
    <ItemsControl.ItemContainerStyle>
        <Style>
            <Setter Property="Grid.Column" Value="{Binding ColumnIndex}" />
            <Setter Property="Grid.Row" Value="{Binding RowIndex}" />
        </Style>
    </ItemsControl.ItemContainerStyle>
</ItemsControl>
...