С привязкой данных и MVVM все проще. Поначалу сложнее, но в конечном итоге намного проще.
Создайте два класса, Item
и ItemCollection
, которые оба реализуют INotifyPropertyChanged
. Item
должен предоставлять свойство строки Text
, а ItemCollection
должно предоставлять свойство ObservableCollection<Item>
Items
и свойство Item
SelectedItem
.
Заставить конструктор класса ItemCollection
заполнить Items
тестовыми данными и задать SelectedItem
.
Похоже, многое нужно сделать, прежде чем вы приступите к реализации элемента управления вкладками, но, поверьте мне, вам понравится результат. Ваш XAML для TabControl будет выглядеть примерно так:
<TabControl
ItemsSource="{Binding Items}"
SelectedItem="{Binding SelectedItem}">
<TabControl.DataContext>
<local:ItemsCollection/>
</TabControl.DataContext>
<TabControl.Resources>
<DataTemplate DataType="{x:Type local:Item}">
<TextBlock Background="AliceBlue" Text="{Binding Text}"/>
</DataTemplate>
</TabControl.Resources>
<TabControl.ItemContainerStyle>
<Style TargetType="{x:Type TabItem}">
<Style.Setters>
<Setter Property="Header" Value="{Binding Text}"/>
</Style.Setters>
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
Давайте разберемся, что это делает. Это создает TabControl
. Он создает объект ItemsCollection
и устанавливает его как TabControl
DataContext
. Вы связали ItemSource
с Items
, поэтому TabControl
создаст TabItem
для каждого элемента. Он будет применять ItemContainerStyle
к каждому TabItem
, который устанавливает свое свойство Header
в свойство Item
Text
.
Когда элемент управления отображает содержимое вкладки, он находит элемент, который он отображает, просматривает ресурсы, чтобы найти DataTemplate
, чей DataType
соответствует элементу, и использует этот шаблон. Поскольку мы определили его в TabControl.Resources
, вы получите красивый синий фон и свойство Text
снова.
Это, похоже, многое пережить. Но теперь вам не нужно писать код, который манипулирует пользовательским интерфейсом; вы просто пишете код, который манипулирует вашим ItemsCollection
, и пользовательский интерфейс в значительной степени заботится о себе.
Теперь давайте позаботимся о добавлении новых вкладок. Что мы собираемся сделать, это добавить новый элемент в элемент управления, который, когда он становится выбранным, добавляет новый элемент в коллекцию Items
.
Создайте новый класс с именем, о, ControlItem
. Имейте это из Item
. Измените конструктор ItemsCollection
, чтобы последний добавленный элемент был ControlItem
, а не Item
. И установите для свойства Text
этого элемента значение «+».
Добавьте этот метод к ItemsCollection
:
public Item AddItem()
{
Item newItem = new Item {Text = "New item"};
Items.Insert(Items.Count-1, newItem);
return newItem;
}
Теперь добавьте код своего окна в качестве обработчика событий SelectionChanged
для вашего TabControl
:
void TabControl_SelectionChanged(object sender, RoutedEventArgs e)
{
TabControl tc = (TabControl) sender;
if (tc.SelectedItem is ControlItem)
{
ItemsCollection ic = (ItemsCollection) tc.DataContext;
tc.SelectedItem = ic.AddItem();
}
}
Вы можете реализовать аналогичную логику для удаления элемента из списка, но вам нужно будет ввести другую переменную в ItemsCollection
для отслеживания ранее выбранного элемента, чтобы вы могли знать, какой элемент удалить.
Еще одна вещь, которую вы можете сделать: реализовать свойство Background
в Item
и добавить установщик в ItemContainerStyle
, который связывает свойство TabItem
Background
с ним. Затем вы можете перегрузить это свойство в ControlItem
, чтобы ваши вкладки добавления и удаления выглядели по-разному.
Вы также можете реализовать различные подклассы для своих элементов управления, и они будут предоставлять метод, который вы вызываете в обработчике события SelectionChanged
. Таким образом, обработчик событий не должен ничего знать о том, что делает элемент управления, по которому щелкают. На самом деле, если вы сделаете метод частью Item
и у вас ничего не будет делать, если он не переопределен, окну даже не нужно знать, что Item
имеет подклассов.
Такова философия MVVM: связать представление с объектами, о которых он почти ничего не знает. Позвольте объектам модели представления управлять тем, что происходит, так что представление не должно.