TabItem标题单击

时间:2011-03-21 17:29:02

标签: wpf controltemplate tabitem

我为我的标签项定义了一个控件模板/样式,如下所示:

<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中的更改来更新活动选项卡内容。感谢

1 个答案:

答案 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