Нажмите заголовок TabItem - PullRequest
       24

Нажмите заголовок TabItem

2 голосов
/ 21 марта 2011

Я определил шаблон / стиль элемента управления для элементов моей вкладки следующим образом:

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

Когда я щелкаю заголовок вкладки, команда, связанная с кнопкой, называется «ОК», однако, по-видимому, событие щелчка сгорело в событии SelectionChanged, и поэтому страница вкладки не изменяется.

Есть ли лучший способ реализовать это, чтобы я мог вызывать метод виртуальной машины и получать изменения на вкладке?

Обновление согласно комментарию

Идея состоит в том, что если пользователь щелкает заголовок текущей активной вкладки, он обновляет содержимое активных вкладок посредством изменений в виртуальной машине. Спасибо

1 Ответ

4 голосов
/ 21 марта 2011

Вот мой способ реализовать такую ​​функциональность, но лучше это или нет - дело вкуса.

Основной 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 (в кодплексе).

Кроме того, не путайте 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);
...