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}}" />
Related
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>
I have a datagrid binded to a collection of custom objects.
This datagrid allows the user to access a context menu when he right clicks a row. I do this through TextBlock styling:
<Style x:Key="DatagridTextblockStyle"
TargetType="{x:Type TextBlock}">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="First action" />
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
It also displays rows which might be disabled if the custom object's "IsActive" bool property is false.
I do this through the DataGrid.RowStyle:
<DataGrid ItemsSource="{Binding MyCustomObjects}">
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsActive}"
Value="True">
<Setter Property="IsEnabled"
Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
</DataGrid>
This works fine.
The problem however is that when a row is disabled, the context menu is not available anymore.
I can't find a way around that.
Any ideas?
Set the ContextMenuService.ShowOnDisabled attached property to true in the ElementStyle:
<Style x:Key="DatagridTextblockStyle" TargetType="{x:Type TextBlock}">
<Setter Property="ContextMenuService.ShowOnDisabled" Value="True" />
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="First action" />
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
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.
I am using DataTrigger to deselect ComboBox with CheckBox (Unchecked == deselected).
What i Need is:
when i select some item from ComboBox then CheckBox need to become
Checked.
When i uncheck CheckBox then ComboBox need to deselect.
CheckBox cannot be checked if ComboBox is deselected (or if ComboBox is deselected after CheckBox is Checked ComboBox should be selected with first item)
Here is XAML (this is working version and need to be changed). Solution must be pure XAML (no C# code)!
<CheckBox HorizontalContentAlignment="Stretch" VerticalContentAlignment="Center" Margin="90,519,13,0" VerticalAlignment="Top" Height="21" Width="Auto">
<CheckBox.Style>
<Style TargetType="{x:Type CheckBox}" BasedOn="{StaticResource {x:Type CheckBox}}">
<Style.Resources>
<Style TargetType="Path">
<Setter Property="FlowDirection" Value="LeftToRight" />
</Style>
<Style TargetType="TextBlock">
<Setter Property="FlowDirection" Value="LeftToRight" />
</Style>
</Style.Resources>
<Setter Property="FlowDirection" Value="RightToLeft" />
<!--<Setter Property="IsChecked" Value="True" />
<Style.Triggers>
<DataTrigger Binding="{Binding SelectedItem, ElementName=comboBoxEventDevice, UpdateSourceTrigger=PropertyChanged}" Value="{x:Null}">
<Setter Property="IsChecked" Value="False" />
</DataTrigger>
</Style.Triggers>-->
</Style>
</CheckBox.Style>
<ComboBox x:Name="comboBoxEventDevice" FlowDirection="LeftToRight" SelectionChanged="comboBoxEventDevice_SelectionChanged" Width="Auto">
<ComboBox.Style>
<Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource {x:Type ComboBox}}">
<Setter Property="SelectedIndex" Value="1" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsChecked, RelativeSource={RelativeSource AncestorType={x:Type CheckBox}}}" Value="True">
<Setter Property="SelectedIndex" Value="0" />
</DataTrigger>
<!--<DataTrigger Binding="{Binding Path=IsChecked, RelativeSource={RelativeSource AncestorType={x:Type CheckBox}}}" Value="False">
<Setter Property="SelectedIndex" Value="1" />
</DataTrigger>-->
</Style.Triggers>
</Style>
</ComboBox.Style>
</ComboBox>
</CheckBox>
UPDATE:
I try to not use nested controls (combobox inside checkbox) so i change XAML bu everything is same as before:
<CheckBox x:Name="checkBoxEventDevice" Margin="70,600,13,0" VerticalAlignment="Top" Height="21"/>
<ComboBox x:Name="comboBoxEventDevice" Margin="90,519,10,0" VerticalAlignment="Top" SelectionChanged="comboBoxEventDevice_SelectionChanged">
<ComboBox.Style>
<Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource {x:Type ComboBox}}">
<Setter Property="SelectedIndex" Value="1" />
<Style.Triggers>
<!--<DataTrigger Binding="{Binding Path=IsChecked, ElementName=checkBoxEventDevice}" Value="True">
<Setter Property="SelectedIndex" Value="0" />
</DataTrigger>-->
<DataTrigger Binding="{Binding Path=IsChecked, ElementName=checkBoxEventDevice}" Value="false">
<Setter Property="SelectedIndex" Value="-1" />
</DataTrigger>
</Style.Triggers>
</Style>
</ComboBox.Style>
</ComboBox>
Problem is in <Setter Property="SelectedIndex" Value="1" /> line. If i remove it then ComboBox is deselected when datatrigger is off but if i keep it then when datatrigger is off combobox is set to second item. So i need some line where i can tell: do nothing, do not deselect combobox, keep current state.
I found solution and these features are satisfied :
When i select some item from ComboBox then CheckBox need to become Checked.
When i uncheck CheckBox then ComboBox need to deselect.
If ComboBox is in deselected state, and when CheckBox is Checked ComboBox should be selected with first item (if items exist elsewhere CheckBox stays checked and ComboBox deselected).
Here is XAML:
<CheckBox HorizontalContentAlignment="Stretch" VerticalContentAlignment="Center" Margin="90,519,13,0" VerticalAlignment="Top" Height="21">
<CheckBox.Style>
<Style TargetType="{x:Type CheckBox}" BasedOn="{StaticResource {x:Type CheckBox}}">
<Style.Resources>
<Style TargetType="Path">
<Setter Property="FlowDirection" Value="LeftToRight" />
</Style>
<Style TargetType="TextBlock">
<Setter Property="FlowDirection" Value="LeftToRight" />
</Style>
</Style.Resources>
<Setter Property="FlowDirection" Value="RightToLeft" />
<Setter Property="IsChecked" Value="True" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=SelectedIndex, ElementName=comboBoxEventDevice}" Value="-1">
<Setter Property="IsChecked" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
<ComboBox x:Name="comboBoxEventDevice" FlowDirection="LeftToRight" SelectionChanged="comboBoxEventDevice_SelectionChanged">
<ComboBox.Style>
<Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource {x:Type ComboBox}}">
<Setter Property="SelectedIndex" Value="0" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsChecked, RelativeSource={RelativeSource AncestorType={x:Type CheckBox}}}" Value="False">
<Setter Property="SelectedIndex" Value="-1" />
</DataTrigger>
</Style.Triggers>
</Style>
</ComboBox.Style>
</ComboBox>
</CheckBox>
Now if someone need WPF nullable ComboBox all what need to do is to simple replace existing Combobox tag in its XAML code with XAML above and change x:Name and ElementName of ComboBox to original ComboBox in these lines:
<DataTrigger Binding="{Binding Path=SelectedIndex, ElementName=comboBoxEventDevice}" Value="-1">
<ComboBox x:Name="comboBoxEventDevice" FlowDirection="LeftToRight" SelectionChanged="comboBoxEventDevice_SelectionChanged">
Also callback for SelectionChanged="comboBoxEventDevice_SelectionChanged" should be changed or removed depending do you need event handling or not.
Margins of CheckBox need to be changed to your margins (and maybe you will need to add Width property but that depends on your project) in line:
<CheckBox HorizontalContentAlignment="Stretch" VerticalContentAlignment="Center" Margin="90,519,13,0" VerticalAlignment="Top" Height="21">
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>