TabControl avec le bouton Ajouter un nouvel onglet (+)

Quelle est la bonne façon d'ajouter un bouton " + " de l'onglet à la fin de tous les onglet éléments dans la barre d'onglets de contrôle onglet dans WPF?

  1. il doit fonctionner correctement avec plusieurs lignes d'en-tête d'onglet.
  2. Il devrait être à la fin de l'onglet tous les éléments
  3. Onglet vélo devrait fonctionner correctement ( Alt+ Onglet), c'est-à-dire le + il faut sauter l'onglet.
  4. Je ne devrais pas avoir à modifier la collection de sources à laquelle je suis lié. Qui est, le contrôle doit être réutilisable.
  5. la solution devrait fonctionner avec MVVM

Enter image description here

enter image description here

pour être plus précis, le bouton devrait apparaître exactement comme un dernier onglet supplémentaire et non comme un bouton séparé quelque part sur la droite de toutes les rangées de bandes d'onglets.

je cherche juste l'approche générale pour faire ça.

Google lance de nombreux exemples, mais si vous creusez un aucun d'eux ne satisfait tous les cinq points ci-dessus.

43
demandé sur NVM 2010-08-12 18:39:57

6 réponses

une solution presque complète utilisant 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

c'est presque complet, parce que le cycle de l'onglet ne saute pas l'onglet'+', et affichera du contenu vide (ce qui n'est pas exactement génial, mais je peux vivre avec jusqu'à ce qu'une meilleure solution se présente...).

33
répondu NVM 2016-06-12 11:55:40

j'ai utilisé une modification du modèle de contrôle de l'onglet et la liaison à la AddNewItemCommand commande dans mon modèle de vue. XAML:

<TabControl x:Class="MyNamespace.MyTabView"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            ItemsSource="{Binding MyItemSource}"
            SelectedIndex="{Binding LastSelectedIndex}"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Control.Template>
        <ControlTemplate TargetType="{x:Type TabControl}">
            <Grid ClipToBounds="true"
                  SnapsToDevicePixels="true"
                  KeyboardNavigation.TabNavigation="Local">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition x:Name="ColumnDefinition0" />
                    <ColumnDefinition x:Name="ColumnDefinition1"
                                      Width="0" />
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition x:Name="RowDefinition0"
                                   Height="Auto" />
                    <RowDefinition x:Name="RowDefinition1"
                                   Height="*" />
                </Grid.RowDefinitions>
                <StackPanel Grid.Column="0"
                            Grid.Row="0"
                            Orientation="Horizontal"
                            x:Name="HeaderPanel">
                    <TabPanel x:Name="_HeaderPanel"
                              IsItemsHost="true"
                              Margin="2,2,2,0"
                              KeyboardNavigation.TabIndex="1"
                              Panel.ZIndex="1" />
                    <Button Content="+"
                            Command="{Binding AddNewItemCommand}" />
                </StackPanel>

                <Border x:Name="ContentPanel"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}"
                        Background="{TemplateBinding Background}"
                        Grid.Column="0"
                        KeyboardNavigation.DirectionalNavigation="Contained"
                        Grid.Row="1"
                        KeyboardNavigation.TabIndex="2"
                        KeyboardNavigation.TabNavigation="Local">
                    <ContentPresenter x:Name="PART_SelectedContentHost"
                                      ContentSource="SelectedContent"
                                      Margin="{TemplateBinding Padding}"
                                      SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                </Border>
            </Grid>
            <ControlTemplate.Triggers>
                <Trigger Property="TabStripPlacement"
                         Value="Bottom">
                    <Setter Property="Grid.Row"
                            TargetName="HeaderPanel"
                            Value="1" />
                    <Setter Property="Grid.Row"
                            TargetName="ContentPanel"
                            Value="0" />
                    <Setter Property="Height"
                            TargetName="RowDefinition0"
                            Value="*" />
                    <Setter Property="Height"
                            TargetName="RowDefinition1"
                            Value="Auto" />
                    <Setter Property="Margin"
                            TargetName="HeaderPanel"
                            Value="2,0,2,2" />
                </Trigger>
                <Trigger Property="TabStripPlacement"
                         Value="Left">
                    <Setter Property="Orientation"
                            TargetName="HeaderPanel"
                            Value="Vertical" />
                    <Setter Property="Grid.Row"
                            TargetName="HeaderPanel"
                            Value="0" />
                    <Setter Property="Grid.Row"
                            TargetName="ContentPanel"
                            Value="0" />
                    <Setter Property="Grid.Column"
                            TargetName="HeaderPanel"
                            Value="0" />
                    <Setter Property="Grid.Column"
                            TargetName="ContentPanel"
                            Value="1" />
                    <Setter Property="Width"
                            TargetName="ColumnDefinition0"
                            Value="Auto" />
                    <Setter Property="Width"
                            TargetName="ColumnDefinition1"
                            Value="*" />
                    <Setter Property="Height"
                            TargetName="RowDefinition0"
                            Value="*" />
                    <Setter Property="Height"
                            TargetName="RowDefinition1"
                            Value="0" />
                    <Setter Property="Margin"
                            TargetName="HeaderPanel"
                            Value="2,2,0,2" />
                </Trigger>
                <Trigger Property="TabStripPlacement"
                         Value="Right">
                    <Setter Property="Orientation"
                            TargetName="HeaderPanel"
                            Value="Vertical" />
                    <Setter Property="Grid.Row"
                            TargetName="HeaderPanel"
                            Value="0" />
                    <Setter Property="Grid.Row"
                            TargetName="ContentPanel"
                            Value="0" />
                    <Setter Property="Grid.Column"
                            TargetName="HeaderPanel"
                            Value="1" />
                    <Setter Property="Grid.Column"
                            TargetName="ContentPanel"
                            Value="0" />
                    <Setter Property="Width"
                            TargetName="ColumnDefinition0"
                            Value="*" />
                    <Setter Property="Width"
                            TargetName="ColumnDefinition1"
                            Value="Auto" />
                    <Setter Property="Height"
                            TargetName="RowDefinition0"
                            Value="*" />
                    <Setter Property="Height"
                            TargetName="RowDefinition1"
                            Value="0" />
                    <Setter Property="Margin"
                            TargetName="HeaderPanel"
                            Value="0,2,2,2" />
                </Trigger>
                <Trigger Property="IsEnabled"
                         Value="false">
                    <Setter Property="Foreground"
                            Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </Control.Template>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="5" />
                    <ColumnDefinition Width="Auto" />
                </Grid.ColumnDefinitions>
                <TextBlock Text="{Binding Caption}" />
                <Button Content="x"
                        Grid.Column="2"
                        VerticalAlignment="Top"/>
            </Grid>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</TabControl>

Code dans le modèle de vue ressemble à ceci:

public ICommand AddNewItemCommand
{
    get
    {
        return new DelegateCommand((param) =>
        {
            MyItemSource.Add(CreateMyValueViewModel());
        },
        (param) => MyItemSource != null);
    }
}

attention: J'ai enveloppé TabPanel par StackPanel pour appuyer sur le bouton " + " avec TabPanel quant à la valeur de la propriété " TabStripPlacement". Sans héritage et sans code-behind dans votre vue.

4
répondu Mr.B 2016-06-12 11:58:13

je crois que j'ai trouvé une solution complète, j'ai commencé avec la solution de NVM pour créer mon modèle. Puis Référencé le code source de DataGrid pour trouver un TabControl étendu capable d'ajouter et de supprimer des éléments.

ExtendedTabControl.cs

public class ExtendedTabControl : TabControl
{
    public static readonly DependencyProperty CanUserAddTabsProperty = DependencyProperty.Register("CanUserAddTabs", typeof(bool), typeof(ExtendedTabControl), new PropertyMetadata(false, OnCanUserAddTabsChanged, OnCoerceCanUserAddTabs));

    public bool CanUserAddTabs
    {
        get { return (bool)GetValue(CanUserAddTabsProperty); }
        set { SetValue(CanUserAddTabsProperty, value); }
    }

    public static readonly DependencyProperty CanUserDeleteTabsProperty = DependencyProperty.Register("CanUserDeleteTabs", typeof(bool), typeof(ExtendedTabControl), new PropertyMetadata(true, OnCanUserDeleteTabsChanged, OnCoerceCanUserDeleteTabs));

    public bool CanUserDeleteTabs
    {
        get { return (bool)GetValue(CanUserDeleteTabsProperty); }
        set { SetValue(CanUserDeleteTabsProperty, value); }
    }

    public static RoutedUICommand DeleteCommand
    {
        get { return ApplicationCommands.Delete; }
    }

    public static readonly DependencyProperty NewTabCommandProperty = DependencyProperty.Register("NewTabCommand", typeof(ICommand), typeof(ExtendedTabControl));

    public ICommand NewTabCommand
    {
        get { return (ICommand)GetValue(NewTabCommandProperty); }
        set { SetValue(NewTabCommandProperty, value); }
    }

    private IEditableCollectionView EditableItems
    {
        get { return (IEditableCollectionView)Items; }
    }

    private bool ItemIsSelected
    {
        get
        {
            if (this.SelectedItem != CollectionView.NewItemPlaceholder)
                return true;

            return false;
        }
    }

    private static void OnCanExecuteDelete(object sender, CanExecuteRoutedEventArgs e)
    {
        ((ExtendedTabControl)sender).OnCanExecuteDelete(e);
    }

    private static void OnCanUserAddTabsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ((ExtendedTabControl)d).UpdateNewItemPlaceholder();
    }

    private static void OnCanUserDeleteTabsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        // The Delete command needs to have CanExecute run.
        CommandManager.InvalidateRequerySuggested();
    }

    private static object OnCoerceCanUserAddTabs(DependencyObject d, object baseValue)
    {
        return ((ExtendedTabControl)d).OnCoerceCanUserAddOrDeleteTabs((bool)baseValue, true);
    }

    private static object OnCoerceCanUserDeleteTabs(DependencyObject d, object baseValue)
    {
        return ((ExtendedTabControl)d).OnCoerceCanUserAddOrDeleteTabs((bool)baseValue, false);
    }

    private static void OnExecutedDelete(object sender, ExecutedRoutedEventArgs e)
    {
        ((ExtendedTabControl)sender).OnExecutedDelete(e);
    }

    private static void OnSelectionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (e.NewValue == CollectionView.NewItemPlaceholder)
        {
            var tc = (ExtendedTabControl)d;

            tc.Items.MoveCurrentTo(e.OldValue);
            tc.Items.Refresh();
        }
    }

    static ExtendedTabControl()
    {
        Type ownerType = typeof(ExtendedTabControl);

        DefaultStyleKeyProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(typeof(ExtendedTabControl)));
        SelectedItemProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(OnSelectionChanged));

        CommandManager.RegisterClassCommandBinding(ownerType, new CommandBinding(DeleteCommand, new ExecutedRoutedEventHandler(OnExecutedDelete), new CanExecuteRoutedEventHandler(OnCanExecuteDelete)));
    }

    protected virtual void OnCanExecuteDelete(CanExecuteRoutedEventArgs e)
    {
        // User is allowed to delete and there is a selection.
        e.CanExecute = CanUserDeleteTabs && ItemIsSelected; 
        e.Handled = true;
    }

    protected virtual void OnExecutedDelete(ExecutedRoutedEventArgs e)
    {
        if (ItemIsSelected)
        {
            int indexToSelect = -1;

            object currentItem = e.Parameter ?? this.SelectedItem;
            if (currentItem == this.SelectedItem)
                indexToSelect = Math.Max(this.Items.IndexOf(currentItem) - 1, 0);

            if (currentItem != CollectionView.NewItemPlaceholder)
                EditableItems.Remove(currentItem);

            if (indexToSelect != -1)
            {
                // This should focus the row and bring it into view. 
                SetCurrentValue(SelectedItemProperty, this.Items[indexToSelect]);
            }
        }

        e.Handled = true;
    }

    protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
    {
        base.OnItemsSourceChanged(oldValue, newValue);

        CoerceValue(CanUserAddTabsProperty);
        CoerceValue(CanUserDeleteTabsProperty);

        UpdateNewItemPlaceholder();
    }

    protected override void OnSelectionChanged(SelectionChangedEventArgs e)
    {
        if (Keyboard.FocusedElement is TextBox)
            Keyboard.FocusedElement.RaiseEvent(new RoutedEventArgs(LostFocusEvent));

        base.OnSelectionChanged(e);
    }

    private bool OnCoerceCanUserAddOrDeleteTabs(bool baseValue, bool canUserAddTabsProperty)
    {
        // Only when the base value is true do we need to validate
        // that the user can actually add or delete rows. 
        if (baseValue)
        {
            if (!this.IsEnabled)
            {
                // Disabled TabControls cannot be modified. 
                return false;
            }
            else
            {
                if ((canUserAddTabsProperty && !this.EditableItems.CanAddNew) || (!canUserAddTabsProperty && !this.EditableItems.CanRemove))
                {
                    // The collection view does not allow the add or delete action.
                    return false;
                }
            }
        }

        return baseValue;
    }

    private void UpdateNewItemPlaceholder()
    {
        var editableItems = EditableItems;

        if (CanUserAddTabs)
        {
            // NewItemPlaceholderPosition isn't a DP but we want to default to AtEnd instead of None
            // (can only be done when canUserAddRows becomes true).  This may override the users intent
            // to make it None, however they can work around this by resetting it to None after making
            // a change which results in canUserAddRows becoming true.
            if (editableItems.NewItemPlaceholderPosition == NewItemPlaceholderPosition.None)
                editableItems.NewItemPlaceholderPosition = NewItemPlaceholderPosition.AtEnd;
        }
        else
        {
            if (editableItems.NewItemPlaceholderPosition != NewItemPlaceholderPosition.None)
                editableItems.NewItemPlaceholderPosition = NewItemPlaceholderPosition.None;
        }

        // Make sure the newItemPlaceholderRow reflects the correct visiblity 
        TabItem newItemPlaceholderTab = (TabItem)ItemContainerGenerator.ContainerFromItem(CollectionView.NewItemPlaceholder);
        if (newItemPlaceholderTab != null)
            newItemPlaceholderTab.CoerceValue(VisibilityProperty);
    }
}

CustomStyleSelector.cs

internal class CustomStyleSelector : StyleSelector
{
    public Style NewItemStyle { get; set; }

    public override Style SelectStyle(object item, DependencyObject container)
    {
        if (item == CollectionView.NewItemPlaceholder)
            return NewItemStyle;
        else
            return Application.Current.FindResource(typeof(TabItem)) as Style;
    }
}

TemplateSelector.cs

internal class TemplateSelector : DataTemplateSelector
{
    public DataTemplate ItemTemplate { get; set; }
    public DataTemplate NewItemTemplate { get; set; }

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

Générique.xaml

<!-- This style explains how to style a NewItemPlaceholder. -->
<Style x:Key="NewTabItemStyle" TargetType="{x:Type TabItem}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TabItem}">
                <ContentPresenter ContentSource="Header" HorizontalAlignment="Left" />
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<!-- This template explains how to render a tab item with a close button. -->
<DataTemplate x:Key="ClosableTabItemHeader">
    <DockPanel MinWidth="120">
        <Button DockPanel.Dock="Right" Command="ApplicationCommands.Delete" CommandParameter="{Binding}" Content="X" Cursor="Hand" Focusable="False" FontSize="10" FontWeight="Bold" Height="16" Width="16" />
        <TextBlock Padding="0,0,10,0" Text="{Binding DisplayName}" VerticalAlignment="Center" />
    </DockPanel>
</DataTemplate>

<!-- This template explains how to render a tab item with a new button. -->
<DataTemplate x:Key="NewTabItemHeader">
    <Button Command="{Binding NewTabCommand, RelativeSource={RelativeSource AncestorType={x:Type local:ExtendedTabControl}}}" Content="+" Cursor="Hand" Focusable="False" FontWeight="Bold"
            Width="{Binding ActualHeight, RelativeSource={RelativeSource Self}}"/>
</DataTemplate>

<local:CustomStyleSelector x:Key="StyleSelector" NewItemStyle="{StaticResource NewTabItemStyle}" />
<local:TemplateSelector x:Key="HeaderTemplateSelector" ItemTemplate="{StaticResource ClosableTabItemHeader}" NewItemTemplate="{StaticResource NewTabItemHeader}" />
<Style x:Key="{x:Type local:ExtendedTabControl}" BasedOn="{StaticResource {x:Type TabControl}}" TargetType="{x:Type local:ExtendedTabControl}">
    <Setter Property="ItemContainerStyleSelector" Value="{StaticResource StyleSelector}" />
    <Setter Property="ItemTemplateSelector" Value="{StaticResource HeaderTemplateSelector}" />
</Style>
2
répondu Derrick Moeller 2015-01-06 18:55:07

définissez le ControlTemplate du TabControl comme ceci:

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

la rangée supérieure de la grille serait le TabPanel, mais vous le mettriez dans un StackPanel avec un bouton Suivant le TabPanel, et le style le bouton pour ressembler à un onglet.

maintenant le bouton créerait un nouveau TabItem (celui que vous avez créé sur mesure peut-être) et l'ajouterait à la collection Observabled'onglets que vous avez comme source Itemsspour votre TabControl.

2 & 3) il devrait toujours apparaître à la fin, et ce n'est pas un onglet donc j'espère ne pas faire partie de l'onglet cyclisme

4) Eh bien, votre TabControl devrait utiliser une collecte observable de TabItems comme source D'Items à notifier lorsqu'un nouveau est ajouté/supprimé

un peu de code:

Le NewTabButton usercontrol .fichier cs

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

        Header = "+";
    }
}

Et la fenêtre principale:

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

Maintenant, nous devons trouver un moyen de le laisser toujours apparaître en bas à droite et ajouter de l'événement et de style pour elle (le plus le signe est là comme un espace réservé).

1
répondu Ingó Vals 2016-06-12 11:53:41

ce serait probablement mieux comme un commentaire sur la propre solution de @NVM; mais je n'ai pas encore le rep à commenter...

si vous essayez d'utiliser la solution acceptée et que vous n'obtenez pas la commande add pour déclencher alors vous n'avez probablement pas de usercontrol nommé "parentUserControl".

vous pouvez modifier la déclaration TabControl de @NVM comme suit:

<TabControl x:Name="parentUserControl"
            ItemsSource="{Binding Items}"
            ItemTemplateSelector="{StaticResource headerTemplateSelector}"
            ContentTemplateSelector="{StaticResource contentTemplateSelector}"/>

évidemment pas un bon nom pour donner un contrôle de tabulation:); mais je suppose que @NVM avait les données contexte accroché plus haut de son arbre visuel d'un élément pour correspondre au nom.

Note que, personnellement, j'ai préféré utiliser un relatif de liaison en modifiant le code suivant:

<Button Content="+" 
        Command="{Binding ElementName=parentUserControl, 
                          Path=DataContext.NewCommand}"/>

À:

<Button Content="+" 
        Command="{Binding DataContext.NewCommand, 
                          RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}"/>
1
répondu Wizbit 2016-11-15 17:24:35

en plus de la réponse de NVM. Je n'utilise pas autant de modèles et de sélecteurs pour NewItemPlaceholder. Solution plus facile sans contenu vide:

    <TabControl.ItemContainerStyle>
        <Style TargetType="TabItem">
           <Style.Triggers>
              <DataTrigger Binding="{Binding}" Value="{x:Static CollectionView.NewItemPlaceholder}">
                 <Setter Property="Template">
                    <Setter.Value>
                       <ControlTemplate>
                          <Button Command="{Binding DataContext.AddPageCommand, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}"
                                  HorizontalContentAlignment="Center" VerticalContentAlignment="Center" ToolTip="Add page" >
                             +
                          </Button>
                       </ControlTemplate>
                    </Setter.Value>
                 </Setter>
              </DataTrigger>
           </Style.Triggers>
        </Style>
     </TabControl.ItemContainerStyle>

Ctrl + Tab I desired to disable. Ce n'est pas si facile, vous devriez vous inscrire sur KeyDown sur l'élément parent, i.e. Window (Ctrl+Shift+Tab également manipulé correctement):

  public View()
  {
     InitializeComponent();
     AddHandler(Keyboard.PreviewKeyDownEvent, (KeyEventHandler)controlKeyDownEvent);
  }

  private void controlKeyDownEvent(object sender, KeyEventArgs e)
  {
     e.Handled = e.Key == Key.Tab && Keyboard.Modifiers.HasFlag(ModifierKeys.Control);
  }
0
répondu Lev 2016-11-18 12:32:50