ContextMenuコマンドからTabItemを見つける正しい方法
-
19-08-2019 - |
質問
ContextMenuを設定するTabControlがあります。
すべてのContextMenu要素にはコマンドが設定されています。
<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>
すべてのコマンドはルーティングされ、CommandBindingsはTabControlの上のいくつかのレベルで定義されます。
質問は次のとおりです。CommandBindingCanExecute / Executeイベントハンドラーで、メニューが呼び出されたTabItemを見つける正しい方法は何ですか?正確には、TabItemテンプレートのようなものを変更しても壊れないものを意味します。
またはアプローチ全体が間違っている可能性があり、これにルーティングされたコマンドを使用しないでください?元々、ホットキーが必要な[新しいタブを追加]コマンドにルーティングを使用していました。
事前に感謝します。
更新:
Igorのソリューションは、アーキテクチャPOVからはよりクリーンです(ViewModelで_を削除することを除く)が、TabControlがバインドされているものとは独立した再利用可能なCloseコマンドが必要です(すべてのタブにClose / Close Allが存在するため種類のアプリケーションであり、特定のモデルに意味的にリンクされていません。
また、カスタムテンプレートが既にあるため、カスタムDataTemplateを使用できません。サブクラス化すると、ソリューションが少し複雑になります。
解決
自分で答えを見つけたようですが、非常に違法です:
<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>
だから、ContextControlをTabControlではなくTabItemに追加し、CommandTargetをTabItemにバインドします。
より良い答えがあるかどうかは興味深いです。
他のヒント
もちろん、より良い答えがあります。ビューではなく、Model / ViewModelを使用する必要があります。ここに私のコードからの簡単な例:
<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>
このコマンドを処理するコードを次に示します。
地域<!> quot;ページを閉じる<!> quot;
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
終了地域
ご覧のとおり、私のコードでは、どのTabItemがクリックされたかを知る必要はありません。このTabItemにバインドされたデータオブジェクトを知るだけです。とにかく、クリックされたTabItemを知る必要がある場合、ContainerGeneratorオブジェクトとdatatemplateを使用して、それにバインドされたDataオブジェクトで見つけることができます。
ロシアからの最高の願いを込めて!