Get selected TabControl name in DataTrigger binding - wpf

I have two TabControls in my window (tabQueryControl, and tabControl) and I've created style with a ContextMenu which I set to both the TabControls on a tab right click. However, depending on the tabcontrol which has been right clicked, I want to hide some context menu items. This is my code in the Style.
<Style x:Key="OutputContextMenuStyle" TargetType="{x:Type TextBlock}">
<Setter Property="ContextMenu" Value="{DynamicResource OutputContextMenu}"/>
</Style>
<ContextMenu x:Key="OutputContextMenu">
<MenuItem Header="View in DataViewer" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type cw:ChromeWindow}}, Path=DataContext.ViewCommand}" CommandParameter="OutputWindow">
<MenuItem.Icon>
<Image Source="/Data_Viewer;component/Resources/NodeIcons/view_in_dataviewer.png"/>
</MenuItem.Icon>
<MenuItem.Style>
<Style TargetType="MenuItem">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<!-- if the name of the parent tab control is tabQueryControl, we hide this context menu item -->
<DataTrigger Binding="{Binding Path=TabControl.Name, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabControl}}}" Value="tabQueryControl">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=TabControl.Name, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabControl}}}" Value="tabControl">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</MenuItem.Style>
</MenuItem>
</ContextMenu>
In the DataTrigger I try to get the name of the selected tab control, and set the visibility of the menu item depending on the name, but when I run the code the visibility is collapsed in both tabcontrols. I think the issue is in my binding for each data trigger.

First remove TabControl. from binding path.
After the binding works you can find, that the style doesn't work as expected. For both controls the menu item is visible. The problem is, that the triggers do work on the same ContextMenu instance.
To avoid it add x:Shared="false" to the ContextMenu:
<Style x:Key="OutputContextMenuStyle" TargetType="{x:Type TextBlock}">
<Setter Property="ContextMenu" Value="{DynamicResource OutputContextMenu}"/>
</Style>
<ContextMenu x:Key="OutputContextMenu" x:Shared="false">
<MenuItem Header="View in DataViewer" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type cw:ChromeWindow}}, Path=DataContext.ViewCommand}" CommandParameter="OutputWindow">
<MenuItem.Icon>
<Image Source="/Data_Viewer;component/Resources/NodeIcons/view_in_dataviewer.png"/>
</MenuItem.Icon>
<MenuItem.Style>
<Style TargetType="MenuItem">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<!-- if the name of the parent tab control is tabQueryControl, we hide this context menu item -->
<DataTrigger Binding="{Binding Path=Name, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabControl}}}" Value="tabQueryControl">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=Name, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabControl}}}" Value="tabControl">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</MenuItem.Style>
</MenuItem>
</ContextMenu>
So it should work as expected.

Related

Binding #items of a MenuItem to visibility in a CompositeCollection

I have a MenuItem that is populated via an ObservableCollection plus one static MenuItem that i want to display only if the collection is empty.
To do that i am using CompositeCollection, and try to trigger the visibility of the MenuItem via DataTrigger but to no avail.
No matter if i use HasItems or Items.Count, the binding itself seems to be the problem:
<MenuItem x:Name="ClientsList" Header="Clients">
<MenuItem.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{Binding Source={x:Static win32:ClientProcessHandler.ClientProcessList}}" />
<MenuItem Header="No Client.." IsEnabled="False">
<MenuItem.Style>
<Style TargetType="MenuItem">
<Style.Triggers>
<!-- Here is the binding -->
<DataTrigger Binding="{Binding Items.Count, ElementName=ClientsList}" Value="2">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</MenuItem.Style>
</MenuItem>
</CompositeCollection>
</MenuItem.ItemsSource>
<MenuItem.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="IsChecked" Value="{Binding IsSelected, Mode=OneWay}" />
<Setter Property="Header" Value="{Binding Path}" />
<Setter Property="Command" Value="{Binding DataContext.SelectClient, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
<Setter Property="CommandParameter" Value="{Binding }" />
<Setter Property="StaysOpenOnClick" Value="True" />
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
Bind to the Count property of the source collection:
<DataTrigger Binding="{Binding Count,
Source={x:Static win32:ClientProcessHandler.ClientProcessList}}" Value="0">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>

Root MenuItem Visibility binding

I need to a root MenuItem Collapsed based on a condition. I can get sub - MenuItem of the root menu to Collapsed but not the root.
Background: Based on settings I need to MenuItems to be Visible or Collapsed. This kind of works. For sub MenuItem it works perfectly;
<Menu>
<MenuItem Header="Root Menu Item" >
<MenuItem.Style>
<Style TargetType="{x:Type MenuItem}" >
<Setter Property="Visibility" Value="Visible" />
<Style.Triggers>
<DataTrigger Binding="{Binding Source={StaticResource MyResource}, Path=MySetting, UpdateSourceTrigger=PropertyChanged}" Value="False">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</MenuItem.Style>
<MenuItem Header="Sub Menu Item">
<MenuItem.Style>
<Style TargetType="{x:Type MenuItem}" >
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding Source={StaticResource MyResource}, Path=MySetting, UpdateSourceTrigger=PropertyChanged}" Value="False">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</MenuItem.Style>
</MenuItem>
</MenuItem>
</Menu>
Changing the value for MySetting between true and false makes the "Sub Menu Item" disappear or a appear, but has no effect on the Root Menu Item. I am at a lost as to why.
For this simple Binding it's better and easier to use an IValueConverter, e.g. the preincluded BooleanToVisibilityConverter.
Usage example:
<SomeParentElement.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
</SomeParentElement.Resources>
<Menu Visibility="{Binding Path=MySetting,
Source={StaticResource MyResource},
Converter={StaticResource BoolToVisConverter}}" />

How to hide the menu item of context menu in wpf xaml based on condition

In my xaml, I have used wpf ContextMenu to display the menu items in wpf datagid. I need to hide the menu items based on the condition. I tried the following but its not working.
<ContextMenu x:Key="contextMenuTextCell">
<MenuItem Name="copyDealContextMenu"
Header="Copy Deal"
Command="{Binding RelativeSource={RelativeSource AncestorType=DataGrid}, Path=DataContext.CopyDeal}"
CommandParameter="{Binding}">
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Visibility" Value="Collapsed"></Setter>
<Style.Triggers>
<DataTrigger Binding="{ Binding ElementName= BlotGrid,Path=DataContext.ProductType }" Value="FXO">
<Setter Property="Visibility" Value="Visible"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</MenuItem>
</ContextMenu>
How to hide the menu items in context menu?
Thanks
There are 2 reason this did not work.
1) is that ContextMenu does not reside in the same VisualTree as the element it is set for ( i.e. it's PlacementTarget). There for you would not be able to bind to an element with ElementName.
2) you put your Style like it's a Content of the MenuItem. ( I didn't notice it at first as well..). it needs to be set to the DependencyProperty 'Style' of your MenuItem.
<Grid x:Name="BlotGrid" Background="Red">
<Grid.ContextMenu>
<ContextMenu>
<MenuItem Name="copyDealContextMenu"
Header="Copy Deal"
CommandParameter="{Binding}">
<MenuItem.Style>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Visibility" Value="Collapsed"></Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu},Path=PlacementTarget.DataContext.IsXXX}" Value="True">
<Setter Property="Visibility" Value="Visible"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</MenuItem.Style>
</MenuItem>
</ContextMenu>
</Grid.ContextMenu>
</Grid>

ContextMenu not updating parent change

I have following, straightforward example
<ContextMenu x:Shared="false">
<MenuItem Header="UsuĊ„" CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Parent}"/>
<MenuItem CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Parent}">
<MenuItem.Style>
<Style TargetType="MenuItem">
<Setter Property="Header" Value="On"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Parent.IsEnabled}" Value="False">
<Setter Property="Header" Value="Off"/>
</DataTrigger>
</Style.Triggers>
</Style>
</MenuItem.Style>
</MenuItem>
</ContextMenu>
For the first time when it is created it sets Header's value to On, but in time property IsEnabled is set to false and no change is reflected. Any help would be appreciated.
In this case it seems like it's because the element's Parent didn't change. Try using a different RelativeSource (example untested):
<DataTrigger Binding="{Binding IsEnabled, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1}}"
Value="False">

WPF Styling and Templating over many buttons?

I can't seem to get the correct combination to get the desired effect:
Current XAML:
<Button Content="Foo" prism:Click.Command="{Binding FooCommand}"
Visibility="{Binding IsEnabled, RelativeSource={RelativeSource Self}, Converter={ncon:VisibilityBooleanConverter}}" />
<Button Content="Bar" prism:Click.Command="{Binding BarCommand}"
Visibility="{Binding IsEnabled, RelativeSource={RelativeSource Self}, Converter={ncon:VisibilityBooleanConverter}}" />
I want to extract out the Visibility="{Binding IsEnabled, RelativeSource={RelativeSource Self}, Converter={ncon:VisibilityBooleanConverter}}" as a style to apply over all the Buttons (within this UserControl resources). I can't seem to get the correct combination going here to make that happen.
Basically, what it does is instead of just disabling the button based on the ICommand.CanExecute it takes that DependencyProperty and binds it to the Visibility of the Button using a boolean-visiblity converter so the button is not only disabled, but also collapsed.
Style would look like this i suppose:
<Style TargetType="{x:Type Button}">
<Setter Property="Visibility"
Value="{Binding IsEnabled, RelativeSource={RelativeSource Self}, Converter={ncon:VisibilityBooleanConverter}}"/>
</Style>
Doesn't that work?
<Style x:Key="ButtonStyle" TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsEnabled, RelativeSource={RelativeSource Self}, Converter={ncon:VisibilityBooleanConverter}}" Value="Visible">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>

Resources