Pregunta

Tengo el TabControl en el que estoy configurando el ContextMenu.

Todos los elementos de ContextMenu tienen comandos establecidos.

<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 los comandos se enrutan, y CommandBindings se definen varios niveles por encima del TabControl.

Entonces, la pregunta es: en los controladores de eventos CommandExplorar CanExecute / Execute, ¿cuál es la forma correcta de averiguar en qué TabItem se invocó el menú? Por correcto quiero decir el que no se rompería si cambio algo como la plantilla TabItem.

¿O puede ser que todo el enfoque es incorrecto y no debería usar comandos enrutados para esto? Originalmente utilicé el enrutamiento para el comando Agregar nueva pestaña que requiere teclas de acceso rápido.

Gracias de antemano.

ACTUALIZACIÓN :

La solución de Igor es más limpia del POV arquitectónico (excepto que eliminaría _ en ViewModel), pero quiero tener un comando de cierre reutilizable que sea independiente de lo que está vinculado TabControl (ya que Cerrar / Cerrar todo para pestañas existe en todos tipos de aplicaciones y no están semánticamente vinculados a un modelo específico).

Además, no puedo usar DataTemplate personalizado ya que ya tengo una plantilla personalizada, y su subclasificación haría que la solución sea un poco complicada.

¿Fue útil?

Solución

Parece que he encontrado la respuesta por mí mismo, sin embargo, es muy poco elegante:

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

Entonces agrego ContextMenu a TabItem en lugar de TabControl, y asocio CommandTarget a TabItem.

Es interesante si hay una mejor respuesta.

Otros consejos

Claro, hay una mejor respuesta. Debe trabajar con Model / ViewModel, no view. Aquí un ejemplo simplificado de mi 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>

Aquí está el código, que maneja este comando.

Región " Cerrar 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

Región final

Como puede ver, mi código no necesita saber en qué TabItem se hizo clic, solo necesito saber qué objeto de datos estaba vinculado a este TabItem. De todos modos, si necesita saber TabItem, en el que se hizo clic, puede encontrarlo por el objeto de datos enlazado a él usando el objeto ContainerGenerator y su plantilla de datos.

¡Con los mejores deseos de Rusia!

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top