Pergunta

Eu tenho o TabControl em que estou definindo o ContextMenu.

elementos Todos ContextMenu ter comandos definido.

<ContextMenu x:Key="tabMenu">
  <MenuItem Command="{x:Static tabs:TabCommands.Close}" />
  <MenuItem Command="{x:Static tabs:TabCommands.CloseAllButThis}" />
  <MenuItem Command="{x:Static tabs:TabCommands.CloseAll}" />
</ContextMenu>

Todos os comandos são encaminhadas, e CommandBindings são definidos vários níveis acima do TabControl.

Então a questão é: na CommandBinding CanExecute / Executar manipuladores de eventos, o que é a maneira correta de descobrir em que TabItem o menu foi invocado? Por correta quero dizer o que não quebrou Se eu mudar algo como o modelo TabItem.

Ou pode ser que toda a abordagem é errada e que eu não deveria usar comandos roteados para isso? Eu originalmente usado encaminhamento para Add comando New Tab que requer hotkeys.

Agradecemos antecipadamente.

Atualizar :

A solução de Igor é mais limpo do POV arquitetura (exceto que eu iria remover _ em ViewModel), mas eu quero ter um comando Fechar reutilizável que é independente do que TabControl é obrigado a (desde fim / Fechar tudo para existem guias em todos tipos de aplicações e não são semanticamente ligadas a um modelo específico).

Além disso, eu não posso usar DataTemplate costume desde que eu já tem um modelo personalizado e subclasse que faria solução um pouco demasiado complicada.

Foi útil?

Solução

Parece que eu ter encontrado a resposta me, no entanto, é altamente unelegant:

<Style TargetType="MenuItem">
  <Setter Property="CommandTarget">
    <Setter.Value>
      <Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}"
               Path="(ContextMenu.PlacementTarget)" />
    </Setter.Value>
  </Setter>
</Style>

<Style TargetType="TabItem">
  <Setter Property="ContextMenu" Value="{StaticResource tabMenu}" />
</Style>

Então eu adicionar o ContextMenu para TabItem vez de TabControl, e se ligam CommandTarget ao TabItem.

É interessante saber se existe uma resposta melhor.

Outras dicas

Claro, há uma resposta melhor. Você precisa trabalhar com Model / ViewModel, não ver. Aqui, um exmaple simplificada do meu código:

        <TabControl Margin="3" Grid.Column="1" Name="tbPages"
                    ItemsSource="{Binding DsmProject.Pages}" 
                    ItemTemplate="{DynamicResource TabItemTemplate}"
                    IsSynchronizedWithCurrentItem="True">
        </TabControl>
<DataTemplate x:Key="TabItemTemplate">
    <StackPanel Orientation="Horizontal" ContextMenu="{DynamicResource cmPages}">
        <ContentPresenter Content="{Binding Path=Name}"/>
    </StackPanel>
</DataTemplate>
<ContextMenu x:Key="cmPages">
    <MenuItem Header="Close" Command="cmd:DSM2100Commands.ClosePage" CommandParameter="{Binding}" />
</ContextMenu>

Aqui está o código, que lida com este comando.

Região "Close página"

    Private Sub ClosePageCmd(ByVal sender As Object, ByVal e As ExecutedRoutedEventArgs)
        ViewModel_.History.TakeCommmand(New cmdRemovePage(ViewModel_, e.Parameter))
    End Sub

    Private Sub CanClosePageCmd(ByVal sender As Object, ByVal e As CanExecuteRoutedEventArgs)
        e.CanExecute = ViewModel_.DsmProject IsNot Nothing AndAlso ViewModel_.DsmProject.Pages.Count > 1
    End Sub

End Região

Como você pode ver, o meu código não tem necessidade de saber que TabItem foi clicado, só precisa saber qual objeto de dados foi obrigado a este TabItem. De qualquer maneira, se você precisa saber TabItem, que foi clicado você pode encontrá-lo objeto de dados limitado a ele usando o objeto ContainerGenerator e seu datatemplate.

Com os melhores votos de Rússia!

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top