Как сделать рабочие кнопки в TabItem-е для добавления/удаления TabItem-ов?
Разбираюсь с WPF, .NET-7. Пытаюсь сделать что-то типа меню с табами, стараюсь реализовать через TabControl, в котором возможно будет динамически добавлять и удалять определённые TabItem-ы. Шаблон итемов сделал, чтобы при добавлении добавлялись кнопки, сейчас пытаюсь через команды их добавлять и удалять, но так работает только с нижними кнопками добавления/удаления, но только не работает удаление, хотя команда срабатывает. В чём проблема и как лучше реализовать данную задачу?
TabModel.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace TestProject
{
public class TabModel: INotifyPropertyChanged
{
private string title;
public string Title
{
get { return title; }
set
{
title = value;
OnPropertyChanged("Title");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string prop = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
}
ApplicationViewModel.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace TestProject
{
public class ApplicationViewModel : INotifyPropertyChanged
{
private TabModel selectedTab;
public ObservableCollection<TabModel> Tabs { get; set; }
private RelayCommand addCommand;
public RelayCommand AddCommand
{
get
{
return addCommand ??
(addCommand = new RelayCommand(obj =>
{
MessageBox.Show("add tab");
TabModel tab = new TabModel{ Title = "New Tab" };
Tabs.Add(tab);
SelectedTab = tab;
}));
}
}
private RelayCommand removeCommand;
public RelayCommand RemoveCommand
{
get
{
return removeCommand ??
(removeCommand = new RelayCommand(obj =>
{
MessageBox.Show("remove tab");
TabModel tab = obj as TabModel;
if (tab != null)
{
Tabs.Remove(tab);
}
},
(obj) => Tabs.Count > 0));
}
}
public TabModel SelectedTab
{
get { return selectedTab; }
set
{
selectedTab = value;
OnPropertyChanged("SelectedTab");
}
}
public ApplicationViewModel()
{
Tabs = new ObservableCollection<TabModel>
{
new TabModel { Title="Tab 1" },
new TabModel { Title="Tab 2" },
new TabModel { Title="Tab 3" },
new TabModel { Title="Tab 4" }
};
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string prop = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
}
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace TestProject
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ApplicationViewModel();
}
}
}
RelayCommand.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace TestProject
{
public class RelayCommand : ICommand
{
private Action<object> execute;
private Func<object, bool> canExecute;
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
this.execute = execute;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return this.canExecute == null || this.canExecute(parameter);
}
public void Execute(object parameter)
{
this.execute(parameter);
}
}
}
MainWindow.xaml
<Window x:Class="TestProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TestProject"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TabControl Grid.Column="0" SelectedItem="{Binding SelectedTab}" ItemsSource="{Binding Tabs}">
<TabControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Title}"/>
<Button Command="{Binding AddCommand}" Content="+"/>
<Button Command="{Binding RemoveCommand}"
CommandParameter="{Binding SelectedTab}"
Content="-"/>
</StackPanel>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
<StackPanel Grid.Row="1" Orientation="Horizontal">
<Button Command="{Binding AddCommand}"
Width="50"
Height="50">+</Button>
<Button Command="{Binding RemoveCommand}"
CommandParameter="{Binding SelectedPhone}"
Width="50"
Height="50">-</Button>
</StackPanel>
</Grid>
</Window>
Источник: Stack Overflow на русском