這是我實現這種功能的方式,但是不管它好不好 - 這是品味的問題。
主要XAML看起來如此:
<TabControl ItemsSource="{Binding TabItems}">
<TabControl.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Title}"/>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<local:ExecuteCommandAction Command="{Binding HeaderClickCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Grid>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
沒有ControlTemplate
,只是DataTemplate
與附加屬性Interaction.Triggers
,其中前綴i
在這個字符串的定義:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
這個庫可以在MS Blend SDK或庫mvvm燈(在codeplex上)中找到。
此外,不要混淆EventTriggers
具有前綴i
和通用EventTriggers,他們在某一點不同,但我不知道兩者的區別是什麼,除了從自定義庫工作EventTrigger
類Silverlight
。
在我的示例中,觸發器訂閱了事件MouseLeftButtonDown
,並在每次引發事件時調用特殊操作類。 這個動作類是一個自定義類,它是在代碼中定義:
/// <summary>
/// Behaviour helps to bind any RoutedEvent of UIElement to Command.
/// </summary>
[DefaultTrigger(typeof(UIElement), typeof(System.Windows.Interactivity.EventTrigger), "MouseLeftButtonDown")]
public class ExecuteCommandAction : TargetedTriggerAction<UIElement>
{
/// <summary>
/// Dependency property represents the Command of the behaviour.
/// </summary>
public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.RegisterAttached("CommandParameter",
typeof(object), typeof(ExecuteCommandAction), new FrameworkPropertyMetadata(null));
/// <summary>
/// Dependency property represents the Command parameter of the behaviour.
/// </summary>
public static readonly DependencyProperty CommandProperty = DependencyProperty.RegisterAttached("Command",
typeof(ICommand), typeof(ExecuteCommandAction), new FrameworkPropertyMetadata(null));
/// <summary>
/// Gets or sets the Commmand.
/// </summary>
public ICommand Command
{
get
{
return (ICommand)this.GetValue(CommandProperty);
}
set
{
this.SetValue(CommandProperty, value);
}
}
/// <summary>
/// Gets or sets the CommandParameter.
/// </summary>
public object CommandParameter
{
get
{
return this.GetValue(CommandParameterProperty);
}
set
{
this.SetValue(CommandParameterProperty, value);
}
}
/// <summary>
/// Invoke method is called when the given routed event is fired.
/// </summary>
/// <param name="parameter">
/// Parameter is the sender of the event.
/// </param>
protected override void Invoke(object parameter)
{
if (this.Command != null)
{
if (this.Command.CanExecute(this.CommandParameter))
{
this.Command.Execute(this.CommandParameter);
}
}
}
}
這是所有。現在該命令不會阻止tabcontrol選擇項目。 代碼隱藏來測試此XAML:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var items = new ObservableCollection<TabItemViewModel>
{
new TabItemViewModel("Item 1"), new TabItemViewModel("Item 2"), new TabItemViewModel("Item 3")
};
this.DataContext = new MainViewModel(){TabItems = items};
}
}
public class MainViewModel
{
public ObservableCollection<TabItemViewModel> TabItems { get; set; }
}
public class TabItemViewModel
{
public TabItemViewModel(string title)
{
this.Title = title;
this.HeaderClickCommand = new RelayCommand(() => MessageBox.Show("Clicked "+this.Title));
}
public string Title { get; set; }
public RelayCommand HeaderClickCommand { get; set; }
}
要呼叫選擇了一個項目,只有當該命令,改變此代碼:
<local:ExecuteCommandAction Command="{Binding HeaderClickCommand}"
CommandParameter="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType=TabItem}}"/>
而這個(第二個參數是CanExecute
代表,它支票IsSelected == true
):
this.HeaderClickCommand = new RelayCommand<bool>(b => {/*???*/}, b => b == true);
你想要一個實際的按鈕作爲tabheader,或者你只是想執行一個命令tabchange嗎? – 2011-03-21 18:32:56
嗨,我打算在標題中放一個按鈕。這個想法是,如果用戶單擊標題,它會通過虛擬機中的更改來更新標籤內容。謝謝 – Sidebp 2011-03-21 19:58:44
該按鈕對此功能不太好,最好使用MouseLeftButtonDown事件。我的答案必須幫助你理解我的意思。 – vorrtex 2011-03-21 20:50:28