Trigger for a ContextMenu Visibility? - wpf

I have a Listbox that starts off with no items inside. When a user uses the GUI to select a value from a combobox and clicks the add Button, the the listbox gets an item added. The Listbox also has a contextmenu set.
How can i use XAML to make sure that the Listbox.contextmenu.Visibility property set to hidden when there are no items in the listbox??
UPDATE
I actually used this code in the end. Please comment on its appropriatness
<Style TargetType="ListBox">
<Style.Resources>
<ContextMenu x:Key="cm">
<MenuItem Header="Buy"/>
<MenuItem Header="Sell"/>
</ContextMenu>
</Style.Resources>
<Setter Property="ContextMenu" Value="{StaticResource cm}"/>
<Style.Triggers>
<Trigger Property="ListBox.HasItems" Value="False">
<Setter Property="ContextMenu.Visibility" Value="Hidden"/>
</Trigger>
</Style.Triggers>
</Style>

I do not think that messing with the visibility of the ContextMenu is a good idea, just null out the whole menu if the list is empty.
e.g.
<Style TargetType="{x:Type ListBox}">
<Style.Resources>
<ContextMenu x:Key="cm">
<!-- Menu here -->
</ContextMenu>
</Style.Resources>
<Setter Property="ContextMenu" Value="{StaticResource cm}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Items.Count, RelativeSource={RelativeSource Self}}" Value="0">
<Setter Property="ContextMenu" Value="{x:Null}" />
</DataTrigger>
</Style.Triggers>
</Style>
You could also choose to only define ContextMenus on the items themselves using the ItemContainerStyle, then no ContextMenu can be opened without items but that might of course not fit your scenario.

Related

One DataTrigger for multiple properties

I have a listview bound to an Observable collection, the listview has properties that most of them will use the same trigger.
is it possible to define the trigger once in the resource section and just refer to it once needed by the properties ?
so far i come to this :
<Style TargetType="TextBlock" x:Key="Pstyle">
<Setter Property="Text" Value="Testing"/>
<Style.Triggers>
<DataTrigger Binding="{Binding P1}" Value="Testing">
<Setter Property="Foreground" Value="DarkGreen"/>
<Setter Property="FontWeight" Value="Bold"/>
</DataTrigger>
</Style.Triggers>
</Style>
and in the listview member i just apply the defined style to the propertie P1
Style="{DynamicResource Pstyle}"
but how to apply the same defined trigger for let say P2, P3, P4...
Since you want to put your trigger logic on the content of the TextBlock, in my opinion you should use a Trigger targeting Text property, instead of a DataTrigger.
Check out this sample code:
<Style TargetType="TextBlock" x:Key="Pstyle">
<Style.Triggers>
<Trigger Property="Text" Value="Testing">
<Setter Property="Foreground" Value="DarkGreen"/>
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
</Style.Triggers>
</Style>
<TextBlock Name="MyTextBlock1" Text="MyTextBlock1Text" Style="{StaticResource Pstyle}"/>
<TextBlock Name="MyTextBlock2" Text="MyTextBlock2Text" Style="{StaticResource Pstyle}"/>
<TextBlock Name="MyTextBlock3" Text="MyTextBlock3Text" Style="{StaticResource Pstyle}"/>
as you can see there is only one single style applied to different Textblocks.
Then you should adapt this to your listview.

First item custom style border in ListView

How can I set different style for first item in ListView? In my case, I want to change first item border, to get GUI like this:
My current code (no top border):
<ListView
ItemsSource="{Binding MyData}">
<ListView.ItemContainerStyle>
<Setter Property="BorderThickness" Value="0,0,0,1" />
</ListView.ItemContainerStyle>
</ListView>
There is a very simple solution. You don't have to write custom converters etc. Use PreviousData in RelativeSource
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="BorderThickness" Value="0,0,0,1" />
<Style.Triggers>
<DataTrigger
Binding="{Binding RelativeSource={RelativeSource PreviousData}}" Value="{x:Null}">
<Setter Property="BorderThickness" Value="0,1,0,1"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>

ListBox getting disabled when disable the ListBoxItem in xaml using DataTrigger

I'm tried to disable particular listbox item using the below xaml code,
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}" BasedOn="{StaticResource CustomListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=lvData, Path=SelectedValue.HasDisable}" Value="False">
<Setter Property="IsEnabled" Value="False"/>
<Setter Property="Background" Value="#EBEBEB"/>
<Setter Property="Foreground" Value="Gainsboro"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
When click on a particular listbox item, then item getting disabled based on SelectedValue.HasDisable. after that couldn't make selection on listbox.
Any suggestion???

Treeview ContextMenu binding Cut and Paste to logical tree

This seems like a pretty common scenario but I can't figure out how to bind the menu items to disable when there is nothing in the clipboard.
I've decided against using the Windows clipboard and instead store the actual object in a reference variable on the UserControl called NodeClipboard. Since it is strongly typed and implements INotifyProperty it is a lot more useful to me than the Windows clipboard.
Binding to the individual item works fine though it is extremely verbose because you can't set EventHandlers within resources without using the Style Event Setters.
It sort of looks like this...
<UserControl x:Name="PART_Root">
<TreeView x:Name="PART_Tree" ItemsSource="{Binding ElementName=PART_Root, Path=RootItemContainer}">
<TreeView.Resources>
<ContextMenu x:Key="ContextMenu">
<ContextMenu.Style>
<Style TargetType="ContextMenu">
<!-- I use this event to select the tree view item otherwise it is actually pretty difficult to know what item you right clicked on -->
<EventSetter Event="Opened" Handler="ContextMenu_Opened"/>
</Style>
</ContextMenu.Style>
<MenuItem Header="Cut">
<MenuItem.Style>
<Style TargetType="MenuItem">
<EventSetter Event="Click" Handler="CutNode_Click"/>
<Style.Triggers>
<!-- This binding is fine because it binds to the item that was right clicked on -->
<DataTrigger Binding="{Binding Path=IsRoot}" Value="True">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</MenuItem.Style>
</MenuItem>
<MenuItem Header="Paste">
<MenuItem.Style>
<Style TargetType="MenuItem">
<EventSetter Event="Click" Handler="PasteNode_Click"/>
<!-- This binding always fails because ContextMenu lives outside of the logical tree -->
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=PART_Root, Path=NodeClipboard" Value="{x:Null}">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</MenuItem.Style>
</MenuItem>
</ContextMenu>
<Style TargetType="TreeViewItem">
<Setter Property="ContextMenu" Value="{StaticResource ContextMenu}"/>
</Style>
<HierarchicalDataTemplate DataType="{x:Type local:Node}" ItemsSource="{Binding Path=Children}">
<TextBlock Text="{Binding Path=Id}"/>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
</UserControl>
The key part that doesn't work is this here:
<!-- This binding always fails because ContextMenu lives outside of the logical tree -->
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=PART_Root, Path=NodeClipboard" Value="{x:Null}">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
I've tried using relative source which results in the same problem. The only solution I've thought of so far is making two context menus, one with Paste enabled and one without, and switching the context menu on the style on the TreeViewItem style's ContextMenu setter like so...
<TreeView.Resources>
<Style TargetType="TreeViewItem">
<Setter Property="ContextMenu" Value="{StaticResource ContextMenu_PasteEnabled}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=PART_Root, Path=NodeClipboard" Value="{x:Null}">
<Setter Property="ContextMenu" Value="{StaticResource ContextMenu_PasteDisabled}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TreeView.Resources>
Use the Clipboard class. Then you can use the ContainsText method to determine if there is any data on the clipboard.
http://msdn.microsoft.com/en-us/library/system.windows.forms.clipboard.aspx

Setting the text Colour of a WPF DataGrid Row when row is selected

I'm trying to change the colour of Text in the selected row in a WPF datagrid.
By default it changes the text colour white is there a way to change this using styles / triggers etc?
Thanks in advance!
Try this
<Style x:Key="DataGridCellStyle" TargetType="{x:Type DataGridCell}" >
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="Green"/>
</Trigger>
</Style.Triggers>
</Style>
Then you can use it in the columns that you see fit like
<DataGrid ...>
<DataGrid.Columns>
<DataGridTextColumn CellStyle="{StaticResource DataGridCellStyle}" .../>
If you want it to apply to all columns you can change the x:key of the Style to
<Style x:Key="{x:Type DataGridCell}" TargetType="{x:Type DataGridCell}" >
If you want to completely remove the Foreground color changes (say, if your DataGrid has different colors for different rows), you can do this:
<Style TargetType="{x:Type DataGridCell}" BasedOn="{StaticResource {x:Type DataGridCell}}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="{Binding RelativeSource={RelativeSource Self}, Path=Foreground}" />
</Trigger>
</Style.Triggers>
</Style>
If you want to give this style a name, like in the previous answer, add x:Key.

Resources