Добавить шаблон, полный элементов управления, в другой элемент управления WPF

Итак, я работал над проектом, который позволяет мне добавлять вкладки в элемент управления вкладками и в каждый новый TabItem. У меня есть набор программно сгенерированных элементов управления. Есть ли способ создать шаблон в XAML, который я могу просто добавить к вновь созданному TabItem?

В качестве простого примера скажем, что у меня есть форма WPF с TabPage:

<Window>
 <Grid>
  <TabControl></Tabcontrol>
 </Grid> 
</Window>

И я хочу добавить по 3 кнопки на каждую из своих вкладок.

<Window>
 <Grid>
  <TabControl>
   <TabItem>
    <Button/>
    <Button/>
    <Button/>
   </TabItem>
  </TabControl>
 </Grid> 
</Window>

Я хотел бы иметь возможность редактировать этот шаблон из 3 кнопок в редакторе XAML (вероятно, VS2012), и эти изменения будут отражены в шаблоне, который добавляется к каждому TabItem.

Я огляделся, и большинство статей о шаблонах WPF относятся к шаблонам раскраски или стилей, которые, похоже, не то, что мне нужно. Согласно моему текущему подходу, добавление TabItem программно работает, но делает редактирование шаблона немного более громоздким и, что я считаю, противоречит философии WPF: отключение кода от дизайна.

Я новичок в WPF, но уже вижу его мощь и преимущества по сравнению с WinForms, поэтому я продвигаюсь по этому пути, но поскольку я новичок, моя терминология иногда немного сбивает с толку, что также делает мои попытки поиска неудачными, временами.

Любая помощь будет оценена. Если я недостаточно хорошо объяснил это, дайте мне знать.


person Josh    schedule 04.01.2013    source источник


Ответы (4)


Как упоминал @Olwaro, вы, вероятно, захотите использовать UserControl.

В вашем примере у вас может быть UserControl с этим Xaml (где пользовательский элемент управления называется ThreeButtonStack и находится в пространстве имен WpfApplication2):

<UserControl x:Class="WpfApplication2.ThreeButtonStack"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <UserControl.Resources>
        <Style TargetType="Button">
            <Setter Property="Margin" Value="5" />
            <Setter Property="Width" Value="75" />
        </Style>
    </UserControl.Resources>
    <StackPanel Orientation="Horizontal">
        <Button Content="OK" />
        <Button Content="Cancel" />
        <Button Content="Retry" />
    </StackPanel>
</UserControl>

Затем вы можете вызвать его в своем основном приложении следующим образом:

<Window x:Class="WpfApplication2.TabPageWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:wpfApplication2="clr-namespace:WpfApplication2"
        Title="TabPageWindow" Height="300" Width="300">
    <TabControl>
        <TabItem Header="Tab 1">
            <DockPanel>
                <wpfApplication2:ThreeButtonStack DockPanel.Dock="Bottom" HorizontalAlignment="Right"/>
                <TextBlock>Custom Content</TextBlock>
            </DockPanel>
        </TabItem>
        <TabItem Header="Tab 2">
            <DockPanel>
                <wpfApplication2:ThreeButtonStack DockPanel.Dock="Bottom" HorizontalAlignment="Right"/>
                <TextBox>Editing custom stuff</TextBox>
            </DockPanel>
        </TabItem>
    </TabControl>
</Window>

и результат будет:

Снимок экрана

person Maverik    schedule 07.01.2013
comment
Я предполагаю, что если мне нужно было отредактировать или получить значения из такого шаблона, который содержит текстовые поля и тому подобное, мне просто нужно было бы раскрыть эти свойства, или они легко доступны? - person Josh; 08.01.2013
comment
@Josh да, либо раскрыть новые свойства зависимостей, либо использовать тот факт, что ваш пользовательский элемент управления будет наследовать DataContext из своего контейнера, чтобы вы могли выполнять прямую привязку в UserControl (при условии, что он не изменяется на страницах вкладок) - person Maverik; 08.01.2013

Вы можете попробовать использовать UserControl.

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

person Olwaro    schedule 07.01.2013

TabItem в конечном итоге наследуется от ContentControl, что означает, что вы можете создать его шаблон таким образом, чтобы можно было украсить фактическое содержимое, отображаемое в элементе управления содержимым:

<Style TargetType="TabItem">
  <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="{x:Type TabItem}">
          <Grid>
            <Grid.RowDefinitions>
              <RowDefinition Height="*" />
              <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <ContentPresenter Grid.Row="0" />
            <StackPanel Grid.Row=1>
              <!-- Your buttons -->
            </StackPanel>
          </Grid>
        </ControlTemplate>
      </Setter.Value>
  </Setter>
</Style>

Место, куда вы помещаете ContentPresenter, - это место, где размещается контент ContentControl (или в данном случае TabItem).

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

В качестве альтернативы вы можете оставить TabItem как есть и настроить ContentControl желаемым образом, который вы используете внутри TabItems ...

<TabItem>
  <ContentControl Style="{StaticResource CommonButtons}">
    <!-- TabItem Contents -->
  </ContentControl>
</TabItem>

Конечно, бит ContentControl может оказаться в DataTemplate, и при привязке к ItemsSource вы получите

<TabControl 
   ItemTemplate="{StaticResource CommonButtonsTemplate}" 
   ItemsSource="{Binding MyTabItemsData}" />
person flq    schedule 07.01.2013

Я понятия не имею о классе TabPage, но для решения этой проблемы было бы лучше создать класс, который наследует TabPage и работать с ним, и установить в нем общие функции вместо использования шаблонов. Надеюсь, это поможет.

person yo chauhan    schedule 04.01.2013
comment
Да, это TabItem, извините - обновление исходного сообщения. Создав отдельный класс, унаследованный от него; ничем не отличается от создания метода для возврата TabItem другому методу, который затем добавляет этот TabItem в форму, т.е. программно? - person Josh; 05.01.2013