Добавете шаблон, пълен с контроли, към друга 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 с този 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 и да работите в него, и да зададете обща функционалност в него, вместо да използвате Templateing. Надявам се, че това ще помогне.

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