我为我的标签项定义了一个控件模板/样式,如下所示:
<Style x:Key="TabItemStyle" TargetType="{x:Type TabItem}">
<Setter Property="Header" Value="{Binding Content.DataContext.Header, RelativeSource={RelativeSource Self}}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid Width="Auto" Height="Auto" x:Name="TabItemRoot" Margin="10,0,10,0">
<Button Command="{Binding Content.DataContext.HeaderClickedCommand}">
<ContentPresenter Margin="13,5,13,5"
x:Name="Content"
ContentSource="Header"
RecognizesAccessKey="True">
</ContentPresenter>
</Button>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
当我单击选项卡标题时,绑定到该按钮的命令被称为OK,但是,click事件似乎已经吃掉了SelectionChanged事件,因此标签页不会更改。
有没有更好的方法来实现这一点,以便我可以调用VM方法并仍然可以更改标签页?
根据评论更新
这个想法是,如果用户单击当前活动选项卡的标题,它将通过VM中的更改来更新活动选项卡内容。感谢
答案 0 :(得分:4)
这是我实现此类功能的方法,但是它是否更好 - 这是品味的问题。
主要的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 light(在codeplex上)中找到。
另外,不要混淆具有前缀EventTriggers
的{{1}}和一般的EventTriggers,它们在某些时候是不同的,但我不确切地知道区别是什么,除了{自定义库中的{1}}类也可以使用i
。
在我的示例中,触发器订阅事件EventTrigger
,并在每次引发事件时调用特殊操作类。
此操作类是一个自定义类,它在代码中定义:
Silverlight
就是这样。现在,该命令不会阻止tabcontrol选择项目。 代码隐藏测试这个xaml:
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);
}
}
}
}
这个(第二个参数是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