TabControl с кнопкой добавления новой вкладки (+)

Как правильно добавить вкладку кнопки «+» в конце всех элементов вкладок в полосе вкладок элемента управления вкладками в WPF?

  1. Она должна работать правильно с несколькими строками заголовков вкладок.
  2. Должен быть в конце всех элементов вкладки
  3. Циклирование вкладок должно работать правильно ( Alt + Tab ), то есть + вкладка должна быть пропущена.
  4. Мне не нужно было изменять исходную коллекцию, к которой я привязываю. То есть элемент управления должен быть многоразовым.
  5. Решение должно работать с MVVM

Enter image description here

enter image description here

Чтобы быть более точным, кнопка должна отображаться именно как дополнительная последняя вкладка, а не как отдельная кнопка где-то справа все строки вкладок.

Я просто ищу общий подход к этому.

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

46
задан 18 revs, 3 users 88% 12 June 2016 в 11:59
поделиться

2 ответа

Почти полное решение с использованием IEditableCollectionView:

ObservableCollection<ItemVM> _items;
public ObservableCollection<ItemVM> Items
{
    get
    {
        if (_items == null)
        {
            _items = new ObservableCollection<ItemVM>();
            var itemsView = (IEditableCollectionView)CollectionViewSource.GetDefaultView(_items);
            itemsView.NewItemPlaceholderPosition = NewItemPlaceholderPosition.AtEnd;
        }

        return _items;
    }
}

private DelegateCommand<object> _newCommand;
public DelegateCommand<object> NewCommand
{
    get
    {
        if (_newCommand == null)
        {
            _newCommand = new DelegateCommand<object>(New_Execute);
        }

        return _newCommand;
    }
}

private void New_Execute(object parameter)
{
    Items.Add(new ItemVM());
}
<DataTemplate x:Key="newTabButtonContentTemplate">
    <Grid/>
</DataTemplate>

<DataTemplate x:Key="newTabButtonHeaderTemplate">
    <Button Content="+"
        Command="{Binding ElementName=parentUserControl, Path=DataContext.NewCommand}"/>
</DataTemplate>

<DataTemplate x:Key="itemContentTemplate">
    <Grid/>
</DataTemplate>

<DataTemplate x:Key="itemHeaderTemplate">
    <TextBlock Text="TabItem_test"/>
</DataTemplate>

<vw:TemplateSelector x:Key="headerTemplateSelector"
                           NewButtonTemplate="{StaticResource newTabButtonHeaderTemplate}"
                           ItemTemplate="{StaticResource itemHeaderTemplate}"/>

<vw:TemplateSelector x:Key="contentTemplateSelector"
                            NewButtonTemplate="{StaticResource newTabButtonContentTemplate}"
                            ItemTemplate="{StaticResource itemContentTemplate}"/>

<TabControl ItemsSource="{Binding Items}"
        ItemTemplateSelector="{StaticResource headerTemplateSelector}"
        ContentTemplateSelector="{StaticResource contentTemplateSelector}"/>
public class TemplateSelector : DataTemplateSelector
{
    public DataTemplate ItemTemplate { get; set; }
    public DataTemplate NewButtonTemplate { get; set; }

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        if (item == CollectionView.NewItemPlaceholder)
        {
            return NewButtonTemplate;
        }
        else
        {
            return ItemTemplate;
        }
    }
}

Enter code here

Оно почти полное, потому что цикл вкладок не пропускает вкладку '+', и будет показывать пустое содержимое (что не совсем здорово, но я могу жить с этим, пока не появится лучшее решение...).

34
ответ дан 26 November 2019 в 20:41
поделиться

Определите ControlTemplate для TabControl следующим образом:

 <!-- Sets the look of the Tabcontrol. -->
<Style x:Key="TabControlStyle" TargetType="{x:Type TabControl}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TabControl}">
                <Grid>
                    <!-- Upperrow holds the tabs themselves and lower the content of the tab -->
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="*"/>
                    </Grid.RowDefinitions>

Верхняя строка в grid будет TabPanel, но вы бы поместили это в StackPanel с помощью кнопки, следующей за TabPanel, и стилизовали бы кнопку так, чтобы она выглядела как вкладка.

Теперь кнопка создаст новый TabItem (возможно, ваш пользовательский) и добавит его в ObservableCollection вкладок, которые у вас есть как Itemssource для вашего TabControl.

2 и 3) Он всегда должен появляться в конце, и это не вкладка, так что, надеюсь, не часть цикла вкладок

4) Что ж, ваш TabControl должен использовать ObservableCollection из TabItems в качестве источника элементов, чтобы получать уведомления о новых один добавлен / удален

Некоторый код:

Файл NewTabButton usercontrol .cs

public partial class NewTabButton : TabItem
{
    public NewTabButton()
    {
        InitializeComponent();

        Header = "+";
    }
}

И главное окно:

public partial class Window1 : Window
{
    public ObservableCollection<TabItem> Tabs { get; set; }

    public Window1()
    {
        InitializeComponent();

        Tabs = new ObservableCollection<TabItem>();

        for (int i = 0; i < 20; i++)
        {
            TabItem tab = new TabItem();
            tab.Header = "TabNumber" + i.ToString();
            Tabs.Add(tab);
        }

        Tabs.Add(new NewTabButton());

        theTabs.ItemsSource = Tabs;
    }
}

Теперь нам нужно найти способ, чтобы он всегда отображался внизу справа, а также добавить событие и стиль для него (знак плюса используется в качестве заполнителя).

1
ответ дан 26 November 2019 в 20:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: