I have a WPF system traybar application. When right clicking traybar icon there is a ContextMenu using a HierarchicalDataTemplate to get a 2 level dynamically populated menu. It works but the "clickable" part of the items on the 2nd level does not properly stretch to the available width of the parent control. Instead See picture:
Now the user has to click the darker section (where the text is) of the MenuItem to perform the Command of this item. I want the whole of the menu row to be able to to trigger the Command.
Here is my XAML:
<CollectionViewSource x:Key="Items" Source="{Binding Path=Items}" />
<ContextMenu x:Shared="false" x:Key="Menu" HorizontalContentAlignment="Stretch">
<ContextMenu.ItemTemplate>
<HierarchicalDataTemplate DataType="SystemTrayItemsViewModel" ItemsSource="{Binding Items}">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Converter={StaticResource TabIconConverter}}" />
<TextBlock Text="{Binding Name}" />
</StackPanel>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding Text}" ToolTip="{Binding ToolTip}" Command="{Binding ToClipBoardCommand}" HorizontalContentAlignment="Stretch" />
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</ContextMenu.ItemTemplate>
<ContextMenu.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{Binding Source={StaticResource Items}}">
</CollectionContainer>
<Separator />
<MenuItem Header="Exit" cal:Message.Attach="ExitApplication" />
</CompositeCollection>
</ContextMenu.ItemsSource>
</ContextMenu>
For full source code, check https://github.com/kasperhlund/textgrunt
I just found the answer to this in another SO question.
It seems that the problem is specifying MenuItem within the ItemTemplate. The ContextMenu is apparently wrapping another MenuItem around the ItemTemplate, causing this nesting effect. Istead, you have to do this via the MenuItem's Style:
<ContextMenu>
<ContextMenu.Resources>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Header" Value="{Binding Text}"/>
<Setter Property="ToolTip" Value="{Binding ToolTip}"/>
<Setter Property="Command" Value="{Binding ToClipBoardCommand}"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ContextMenu.Resources>
</ContextMenu>
Related
I'm using a ContextMenu on the right click on a DataGrid. I don't want to show the ContextMenu on the DataGrid header.
<dgWPFCtrl:SelfBindingDataGrid Grid.Row="1" Margin="0,5,0,0" Name="_cycleList"
ItemsSource="{Binding Path=CurrentElementsList, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
IsReadOnly="False"
SelectedItem="{Binding Path=CurrentItem}">
<dgWPFCtrl:SelfBindingDataGrid.ContextMenu>
<ContextMenu>
<MenuItem Command="{Binding OpenCycleCommand}" Header="CYCLE" CommandParameter="CYCLE"/>
<MenuItem Command="{Binding OpenCycleCommand}" Header="H1" CommandParameter="H1"/>
<MenuItem Command="{Binding OpenCycleCommand}" Header="PDF" CommandParameter="PDF"/>
</ContextMenu>
</dgWPFCtrl:SelfBindingDataGrid.ContextMenu>
How can I solve this?
You can change ContextMenu just for the header with ColumnHeaderStyle:
<dgWPFCtrl:SelfBindingDataGrid>
<dgWPFCtrl:SelfBindingDataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu Visibility="Collapsed" />
</Setter.Value>
</Setter>
</Style>
</dgWPFCtrl:SelfBindingDataGrid.ColumnHeaderStyle>
I have a combobox in which first item is checkbox to select all entries from below drop down list. With hard coded string its working fine but now I want to localize it...want to set string from resource file but as its deeply inserted couldn't add it. For that I tried adding panel and one checkbox along with textblock also simply separated textblock from checkbox.
This is code :
<ComboBox Name="CmbEntries" IsTabStop="{Binding CurrentDialogViewModel, Converter={StaticResource NullToBoolConverter}}" Grid.Column="1" Grid.Row="4" VerticalAlignment="Top" Margin="2,0,0,5" SelectedItem="{Binding SelectedEntries}" SelectedIndex="0" HorizontalAlignment="Left" Width="400">
<ComboBox.Resources>
<CollectionViewSource x:Key="EntriesCollection" Source="{Binding DicomDir.Entries}"/>
</ComboBox.Resources>
<ComboBox.ItemsSource>
<CompositeCollection>
<ComboBoxItem>
<CheckBox x:Name="all" Margin="8,0,0,0"
IsChecked="{Binding IsAllEntriessSelected, Mode=TwoWay}"
Command="{Binding SelectAllEntriessCommand}"
CommandParameter="{Binding IsChecked, RelativeSource={RelativeSource Self}}"
**Content="Select All Entries"** />
</ComboBoxItem>
<CollectionContainer Collection="{Binding Source={StaticResource EntriesCollection}}"/>
</CompositeCollection>
</ComboBox.ItemsSource>
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Margin="8,0,0,0"
IsChecked="{ Binding Path=IsAnyEntitySelected, Mode=TwoWay }"
Command="{Binding SelectAllEntityCommand}"
CommandParameter="{Binding IsChecked, RelativeSource={RelativeSource Self}}" />
<TextBlock Margin="5,0,0,0" TextWrapping="Wrap" Text="{Binding DisplayEntriesInfo}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem">
<Style.Triggers>
<DataTrigger Binding="{Binding HasSelectedEntities}" Value="True">
<Setter Property="FontWeight" Value="Bold"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
Scrshot1-Expected
Scrshot2-Actual with Resx
In this case, is it possible to read it directly from resource file?
To bind the content to a resource you do:
<Window ...
xmlns:properties="clr-namespace:YourNamespace.Properties">
<Grid>
<CheckBox Content="{x:Static properties:Resources.Foo}" />
</Grid>
</Window>
For this to work you need Resources to be public.
If it is not you get:
Provide value on 'System.Windows.Markup.StaticExtension' threw an exception...
StaticExtension value cannot be resolved to an enumeration, static field, or static property.
I am having a listbox to which i am binding around 1000usercontrols with itemspaneltemplate as grid and i am placing each usercontrol by specifying rows and columns which is working fine.
But problem is it takes too much of time to load i even used backgroundworker process also but also no use.
Please help me what is the solution for the above problem.
<ListBox VerticalAlignment="Top" ItemsSource="{Binding Session.LstPlannedLightChkEntity,ElementName=uc, IsAsync=True}" Grid.Row="0"
VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling"
local:DragDropHelper.IsDragSource="true" local:DragDropHelper.IsDropTarget="true"
local:DragDropHelper.DragDropTemplate="{StaticResource planetTemplateDrag}"
ScrollViewer.VerticalScrollBarVisibility="Hidden" ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.CanContentScroll="True"
>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Grid.Row" Value="{Binding Row}"/>
<Setter Property="Grid.Column" Value="{Binding Column}"/>
<Setter Property="Grid.ColumnSpan" Value="{Binding ColumnSpan}" />
<Style.Resources>
<!-- Background of selected item when focussed -->
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent"/>
<!-- Background of selected item when not focussed -->
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent" />
</Style.Resources>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<local:GridControl x:Name="gcMenuPlanned" VerticalAlignment="Stretch" Margin="-1,-1,0,0"
ShowCustomGridLines="True" GridLineBrush="#FFE4E7EB" GridLineThickness="0.5" SnapsToDevicePixels="True">
<local:GridControl.ContextMenu>
<ContextMenu >
<MenuItem Foreground="Black" Header="Add Task" Click="AddTask_Click" Tag="{Binding CheckType}" />
<MenuItem Foreground="Black" Header="Goto..." Click="miGoto_Click" Tag="{Binding CheckType}" />
</ContextMenu>
</local:GridControl.ContextMenu>
</local:GridControl>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<local:LightFCCheckBlockControl CheckColor="#FFA2CAEB" MouseLeftButtonDown="LightFCCheckBlockControl_MouseLeftButtonDown">
<local:LightFCCheckBlockControl.ContextMenu>
<ContextMenu >
<MenuItem Foreground="Black" Header="Edit" Click="miEdit_Click" Tag="{Binding CheckType}" Visibility="{Binding Path=OpacityForCCheck,Converter={StaticResource opacityToVisibility}}"/>
<MenuItem Foreground="Black" Style="{StaticResource MenuItemBindingStyle }" Click="miFreeze_Click" Tag="{Binding CheckType}" Visibility="{Binding Path=OpacityForCCheck,Converter={StaticResource opacityToVisibility}}">
</MenuItem>
<MenuItem Foreground="Black" Click="RemoveChecks_Click" Header="Remove Checks" Tag="{Binding CheckType}"/>
<MenuItem Foreground="Black" Click="DeleteChecks_Click" Header="Delete Checks" Tag="{Binding CheckType}" Visibility="{Binding Path=OpacityForCCheck,Converter={StaticResource opacityToVisibility}}"/>
<MenuItem Foreground="Black" Header="Goto..." Click="miGoto_Click" Tag="{Binding CheckType}" Visibility="{Binding Path=OpacityForCCheck,Converter={StaticResource opacityToVisibility}}"/>
</ContextMenu>
</local:LightFCCheckBlockControl.ContextMenu>
</local:LightFCCheckBlockControl>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Thanks
Yogaraj I
Well it sounds a bit odd. First of all, you should answer the question...Is it really necessary to bind 1000 items to a list, which should be shown in UI? The usability would not be the best. Perhaps you could choose an approach with deferred loading.
Second, did you disable the Virtualization in the ListBox? Usually, there are only rendered the visuals for the elements, which are visible. The controls will be reused in case of scrolling.
I'm having a hell of a time trying to dynamically bind the ContextMenu on a DataGrid. The DataGrid is bound to a list of objects which works great:
<DataGrid ItemsSource="{Binding DataGridItems}">
For each of the DataGridItem objects I have a list of MenuItems exposed on a property which I would like to use to bind to the ContextMenu.
I tried the below but I think I’m missing something:
<DataGrid ItemsSource="{Binding DataGridItems}">
<DataGrid.ContextMenu>
<ContextMenu ItemsSource="{Binding ContextMenuItems}" >
<MenuItem Header="{Binding Name}" Command="{Binding OnClick}"></MenuItem>
</ContextMenu>
</DataGrid.ContextMenu>
<DataGrid>
public class DataGridItem
{
public ObservableCollection<ContextMenuItem> ContextMenuItems
{
get { return _contextMenuItems; }
}
}
Any help or guidance would be much appreciated.
This is how I ended up solving it:
<StackPanel.ContextMenu>
<ContextMenu ItemsSource="{Binding ContextMenu}">
<ContextMenu.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Command" Value="{Binding OnClick}" />
<Setter Property="Icon">
<Setter.Value>
<Image Source="{Binding ImageName}"></Image>
</Setter.Value>
</Setter>
</Style>
</ContextMenu.ItemContainerStyle>
<ContextMenu.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type ContextMenu:ContextMenuItem}" ItemsSource="{Binding MenuItems}">
<TextBlock Text="{Binding Name}"></TextBlock>
</HierarchicalDataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
I believe this tutorial describes your issue, but effectively you'd have to do:
<ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}"
ItemsSource="{Binding ContextMenuItems}" />
I have a tree with a hierarchical data template
<HierarchicalDataTemplate DataType="{x:Type local:TreeItem}" ItemsSource="{Binding Path=Children}" >
<TreeViewItem Focusable="True" ToolTip="{Binding ToolTipText}" >
<TreeViewItem.Header>
<StackPanel Orientation="Horizontal" Focusable="True" >
<Image Width="16" Height="16" Margin="3,0">
<Image.Source>
<Binding
Path="IsLeaf" Converter="{StaticResource cnvIsBooleanToStringArrayItemConverter}">
<Binding.ConverterParameter>
<x:Array Type="sys:String">
<sys:String>..\Images\document_plain.png</sys:String>
<sys:String>..\Images\folder.png</sys:String>
</x:Array>
</Binding.ConverterParameter>
</Binding>
</Image.Source>
</Image>
<TextBlock MaxWidth="300" Text="{Binding Desc}" Focusable="True" />
</StackPanel>
</TreeViewItem.Header>
</TreeViewItem>
</HierarchicalDataTemplate>
I want to select an item by clicking at the TextBlock containing "Desc", but the only way to select an item is by clicking in the space left of the text (the image area)
Any clues what is missing?
Regards
Klaus
Your data template specifies a TreeViewItem at its root, but the TreeView will automatically create a TreeViewItem around your template, having a TreeViewItem in a TreeViewItem confuses the selection mechanism.
Do something like this:
<HierarchicalDataTemplate DataType="{x:Type local:TreeItem}" ItemsSource="{Binding Path=Children}">
<HierarchicalDataTemplate.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="ToolTip" Value="{Binding ToolTipText}"/>
<Setter Property="Focusable" Value="True"/>
<Setter Property="Header">
<Setter.Value>
...
</Setter.Value>
</Setter>
</Style>
</HierarchicalDataTemplate.ItemContainerStyle>
</HierarchicalDataTemplate>
Edit:
After some testing it turns out that messing with the container is quite troublesome, i did not get it display the tooltip that way, unless you found a way to do it i recommend you stick to only setting HierarchicalDataTemplate.VisualTree (the default content of HierarchicalDataTemplate) which will be placed in the header of the auto-generated TreeViewItem.
As H.B. says, you should not put a TreeViewItem inside your hierarchical data template, since WPF will automatically create one to wrap your content.
If you want to bind to the ToolTip, you can do it inside the ItemContainerStyle, which will apply to all your treeview items within the TreeView.
<TreeView .... your parameters >
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="ToolTip" Value="{Binding ToolTipText}"/>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
I hope this helps.
Although I haven't tested it, I think your hierarchical data template should look like this:
<HierarchicalDataTemplate DataType="{x:Type local:TreeItem}" ItemsSource="{Binding Path=Children}" >
<StackPanel Orientation="Horizontal">
<Image Width="16" Height="16" Margin="3,0">
<Image.Source>
<Binding Path="IsLeaf" Converter="{StaticResource cnvIsBooleanToStringArrayItemConverter}">
<Binding.ConverterParameter>
<x:Array Type="sys:String">
<sys:String>..\Images\document_plain.png</sys:String>
<sys:String>..\Images\folder.png</sys:String>
</x:Array>
</Binding.ConverterParameter>
</Binding>
</Image.Source>
</Image>
<TextBlock MaxWidth="300" Text="{Binding Desc}"/>
</StackPanel>
</HierarchicalDataTemplate>
You may need to set the Background="Transparent" on the StackPanel and/or remove the Focusable setting on the TextBlock.