Я сомневаюсь, что вам все еще нужна помощь с этим, но решил, что я все равно приму ответ.
Способ, которым я занимался в прошлом, - сделать коллекцию элементов, которые вы привязываете к вашему TabControl, набором простых объектов ViewModel. Таким образом, вы можете реализовать логику CanXXX для каждой вкладки вместо TabControl или представления в целом.
В этом примере я использую класс RelayCommand, показанный в статье Джоша Смита о MVVM .
MainViewModel.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
namespace TabBinding.ViewModels
{
class MainViewModel : ViewModelBase
{
private ObservableCollection<TabViewModel> _Tabs;
public ObservableCollection<TabViewModel> Tabs
{
get { return _Tabs; }
set
{
_Tabs = value;
OnPropertyChanged(this, "Tabs");
}
}
public MainViewModel()
{
var tabs = new ObservableCollection<TabViewModel>();
tabs.Add(new TabViewModel() { TabHeader = "Tab1", Content="Content For Tab1" });
tabs.Add(new TabViewModel() { TabHeader = "Tab2", Content = "Content For Tab2" });
tabs.Add(new TabViewModel() { TabHeader = "Tab3", Content = "Content For Tab3" });
tabs.Add(new TabViewModel() { TabHeader = "Tab4", Content = "Content For Tab4" });
Tabs = tabs;
}
}
}
TabViewModel.cs
using System.Windows.Input;
using System.Windows;
namespace TabBinding.ViewModels
{
class TabViewModel : ViewModelBase
{
RelayCommand _CloseTabCommand;
private string _TabHeader;
public string TabHeader
{
get { return _TabHeader; }
set
{
_TabHeader = value;
OnPropertyChanged(this, "TabHeader");
}
}
private string _Content;
public string Content
{
get { return _Content; }
set
{
_Content = value;
OnPropertyChanged(this, "Content");
}
}
public ICommand CloseTabCommand
{
get
{
if (_CloseTabCommand == null)
{
_CloseTabCommand = new RelayCommand(
param => this.CloseTab(),
param => this.CanCloseTab
);
}
return _CloseTabCommand;
}
}
public void CloseTab()
{
MessageBox.Show("Close Me!");
}
bool CanCloseTab
{
get { return (TabHeader == "Tab2" || TabHeader == "Tab4"); }
}
}
}
ViewModelBase.cs
using System.ComponentModel;
namespace TabBinding.ViewModels
{
class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(object sender, string propertyName)
{
if (this.PropertyChanged != null)
{
PropertyChanged(sender, new PropertyChangedEventArgs(propertyName));
}
}
}
}
RelayCommand.cs
using System;
using System.Diagnostics;
using System.Windows.Input;
namespace TabBinding
{
/// <summary>
/// A command whose sole purpose is to
/// relay its functionality to other
/// objects by invoking delegates. The
/// default return value for the CanExecute
/// method is 'true'.
/// </summary>
public class RelayCommand : ICommand
{
#region Fields
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion // Fields
#region Constructors
/// <summary>
/// Creates a new command that can always execute.
/// </summary>
/// <param name="execute">The execution logic.</param>
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}
/// <summary>
/// Creates a new command.
/// </summary>
/// <param name="execute">The execution logic.</param>
/// <param name="canExecute">The execution status logic.</param>
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion // Constructors
#region ICommand Members
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
#endregion // ICommand Members
}
}
MainWindow.xaml
<Window x:Class="TabBinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:TabBinding.ViewModels"
Title="MainWindow" Height="360" Width="550">
<Window.Resources>
<vm:MainViewModel x:Key="Data" />
</Window.Resources>
<Grid DataContext="{StaticResource Data}">
<TabControl
HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="10,10,10,10"
Width="500"
Height="300"
ItemsSource="{Binding Tabs}">
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button Content="X" Margin="0,0,10,0" Command="{Binding CloseTabCommand}" />
<TextBlock Text="{Binding TabHeader}"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="Content" Value="{Binding Content}"/>
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
</Grid>
</Window>
App.xaml
<Application x:Class="TabBinding.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Views/MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>