Dynamic Bindings in XAML - c#

So I'm trying to alter some XAML code to add in a context menu that will change the number of decimal places of a value. My XAML is a little weak though and I'm getting a bit lost.
The code I have right now is:
<MenuItem Header="{DynamicResource DecimalPlaces}" ItemsSource="{Binding MenuItems}">
<ExclusiveMenuItem:ExclusiveMenuItem Header="{DynamicResource oneDecimal}" IsCheckable="True" IsChecked="{Binding Path=DecimalPlaces}"/>
<ExclusiveMenuItem:ExclusiveMenuItem Header="{DynamicResource twoDecimal}" IsCheckable="True" IsChecked="{Binding Path=DecimalPlaces}"/>
</MenuItem>
This will at least make the menu appear, but the problem is the DecimalPlaces handles ints (I've just put oneDecimal and twoDecimal in as placeholders for now) and I want the dynamic resource to be an int, preferably to go from one to ten too.
So my question is: how can I set the dynamic resource to an integer rather than a specific variable and is there a way to dynamically generate this menu (as opposed to writing 10 different entries), maybe based on an array or something?
Sorry if this is a pretty simple question, like I said, my XAML is a bit weak. Any help greatly appreciated.

If I understand your question correctly, I don't think a DynamicResource is what you need. A DynamicResource is a Resource that will get resolved at Runtime. This is usually used for theming.
It's a little hard to understand exactly what you're trying to do, but if you just want the header to display some text, just set it.
<MenuItem Header="{DynamicResource DecimalPlaces}" ItemsSource="{Binding MenuItems}">
<ExclusiveMenuItem:ExclusiveMenuItem Header="1" IsCheckable="True" IsChecked="{Binding Path=DecimalPlaces}"/>
<ExclusiveMenuItem:ExclusiveMenuItem Header="2" IsCheckable="True" IsChecked="{Binding Path=DecimalPlaces}"/>
<ExclusiveMenuItem:ExclusiveMenuItem Header="OneDecimal" IsCheckable="True" IsChecked="{Binding Path=DecimalPlaces}"/>
<ExclusiveMenuItem:ExclusiveMenuItem Header="TwoDecimal" IsCheckable="True" IsChecked="{Binding Path=DecimalPlaces}"/>
</MenuItem>
If it needs some data coming from your MenuItems, then use an ItemTemplate or ItemContainerStyle.
<MenuItem Header="{DynamicResource DecimalPlaces}" ItemsSource="{Binding MenuItems}">
<MenuItem.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Header" Value="{Binding SomeProperty}" />
<Setter Property="IsCheckable" Value="True" />
<Setter Property="IsChecked" Value="{Binding Path=DecimalPlaces}" />
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>

Related

How to define WPF ContextMenu with a Separator before the last element, using binding on ItemsSource instead of individual MenuItems

I am trying to create a ContextMenu that defines some filters via Checkable MenuItems, with a Separator separating the last MenuItem from the previous ones.
I know I could define and manage the MenuItems and the Separator in the following way:
<ContextMenu HasDropShadow="False" Placement="Bottom">
<MenuItem IsCheckable="True" IsChecked="{Binding Path=IsChecked1}" Header="Filter 1"/>
<MenuItem IsCheckable="True" IsChecked="{Binding Path=IsChecked2}" Header="Filter 2"/>
<MenuItem IsCheckable="True" IsChecked="{Binding Path=IsChecked3}" Header="Filter 3"/>
<MenuItem IsCheckable="True" IsChecked="{Binding Path=IsChecked4}" Header="Filter 4"/>
<MenuItem IsCheckable="True" IsChecked="{Binding Path=IsChecked5}" Header="Filter 5"/>
<MenuItem IsCheckable="True" IsChecked="{Binding Path=IsChecked6}" Header="Filter 6"/>
<MenuItem IsCheckable="True" IsChecked="{Binding Path=IsChecked7}" Header="Filter 7"/>
<MenuItem IsCheckable="True" IsChecked="{Binding Path=IsChecked8}" Header="Filter 8"/>
<Separator Styles.Separator="Default"/>
<MenuItem IsCheckable="True" IsChecked="{Binding Path=IsChecked9}" Header="Active"/>
</ContextMenu>
But I would rather try to avoid having 9 IsChecked properties in my ViewModel, on top of having the next dev need to add/remove a MenuItem and its associated property when we need to add/remove a filter.
What I'd rather do, is to use the ItemsSource property of the ContextMenu and define an ItemTemplate for each element of the ItemsSource. Unfortunately, if I do this, I am not sure how I can define the Separator before the last element of the ItemsSource like I could do in the previous code snippet.
Is there a way to achieve what I want to do without defining manually each individual MenuItem and its associated properties in the ViewModel?
Based on the following answer:
How do I dynamically bind and statically add MenuItems?
I found an hybrid approach to what I wanted to achieve, which makes sense in my context: the only MenuItem I need to manually add is the last one, which I need to handle differently anyway in my ViewModel, so I don't mind manually adding that one. All the others are however generated automatically based on my AllFiltersExceptTheLastOne ObservableCollection:
<UserControl.Resources>
<CollectionViewSource x:Key="AllFiltersExceptTheLastOne" Source="{Binding Path=Filters}"/>
</UserControl.Resources>
...
<Button.ContextMenu>
<ContextMenu HasDropShadow="False" Placement="Bottom">
<ContextMenu.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{Binding Source={StaticResource AllFiltersExceptTheLastOne}}" />
<Separator Margin="0,5,0,5" Styles.Separator="Default"/>
<MenuItem Padding="2,2,2,2" IsCheckable="true" IsChecked="{Binding Path=Filter.IsChecked}" Header="{Binding Path=Filter.Status}" />
</CompositeCollection>
</ContextMenu.ItemsSource>
<ContextMenu.ItemContainerStyle>
<Style>
<Setter Property="MenuItem.Padding" Value="2,2,2,2"/>
<Setter Property="MenuItem.IsCheckable" Value="true"/>
<Setter Property="MenuItem.Header" Value="{Binding Path=Status}"/>
<Setter Property="MenuItem.IsChecked" Value="{Binding Path=IsChecked}"/>
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
</Button.ContextMenu>

Menu item with exactly one checked value

I want to have in my application a context menu "DefaultPrinter" which has some binded childs (another MenuItems) representing printer's names. Each child has a property IsCheckable set to true.
<MenuItem Header="DefaultPrinter" ItemsSource="{Binding AllPrinters}">
<MenuItem.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="IsCheckable" Value="True"/>
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
However, of course I want allow only one printer to be checked (this code doesn't suport that). I looked for solution in the Internet, but didn't find anything helpful.
The problem is that MenuItem derieves from ItemsControl and since that it has no concept of items selection (like Selector). I can try to write my own selection, but first, I would like to know is there better and simplier solution for achieving that goal.
Any help will be appreciated.
Could abuse a hidden RadioButton:
<MenuItem.ItemTemplate>
<DataTemplate>
<Grid>
<RadioButton GroupName="Printers"
IsChecked="{Binding IsChecked, RelativeSource={RelativeSource AncestorType=MenuItem}}"
Visibility="Collapsed"/>
<TextBlock Text="{Binding FullName}"/>
</Grid>
</DataTemplate>
</MenuItem.ItemTemplate>

WPF MenuItem not filling available ContextMenu space

I'm having a weird problem with a simple ContextMenu using MahApps.Metro without any additional styling. When moving the cursor on top of the text or slightly around it, there is no problem. But when moving it further away, still inside the ContextMenu bounds, the Cursor is no longer on top of the MenuItem. Clicking now also doesn't result in any action at all besides closing the ContextMenu.
<ContextMenu ItemsSource="{Binding ContextItems}">
<ContextMenu.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding Text}" Command="{Binding Command}"/>
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
What am I doing wrong? Why doesn't the MenuItem use the available space?
If your ContextItems holds a collection with viewmodels then I think this could help you (not tested):
<ContextMenu ItemsSource="{Binding ContextItems}">
<ContextMenu.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Header" Value="{Binding Text}" />
<Setter Property="Command" Value="{Binding Command}" />
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
Command and Text should be the properties on the viewmodel object.
I havent used MahApps.Metro . Though you can override the template like this
<ContextMenu.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding Text}" Command="{Binding Command}"/>
<MenuItem.Template>
<ControlTemplate>
<ContentPresenter Content="{Binding Header,RelativeSource={RelativeSource TemplatedParent}}">
</ContentPresenter>
</ControlTemplate>
</MenuItem.Template>
</MenuItem>
</DataTemplate>
</ContextMenu.ItemTemplate>
I hope this will help.

Can I set ToolBar items in XAML?

Feel free to suggest an alternate approach to my problem if this isn't the best way to go about it.
I have a ToolBarTray and a TreeView. The tree has 2 items that are Concrete1 and Concrete2 classes respectively. I want the toolbar to have a different menu depending on which type of item is selected in the tree.
<ToolBarTray DockPanel.Dock="Top">
<ToolBar>
<ToolBar.Style>
<Style TargetType="{x:Type ToolBar}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=tree, Path=SelectedItem, Converter={StaticResource convert}}" Value="{x:Type root:Concrete1}">
<!--what do i do here??-->
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=tree, Path=SelectedItem, Converter={StaticResource convert}}" Value="{x:Type root:Concrete2}">
<!--what do i do here??-->
</DataTrigger>
</Style.Triggers>
</Style>
</ToolBar.Style>
<ToolBar.Resources>
<Menu x:Key="awd">
<MenuItem Header="AWD"></MenuItem>
</Menu>
<Menu x:Key="dwa">
<MenuItem Header="DWA"></MenuItem>
</Menu>
</ToolBar.Resources>
</ToolBar>
</ToolBarTray>
<TreeView x:Name="tree" ItemsSource="{Binding Families}"></TreeView>
I've gotten as far as being able to set any regular property (background, etc) of the toolbar depending on which item is selected. I don't know how to proceed to add specific Menus to the toolbar.
I think I've figured it out. I've only done this with a ContextMenu and outside of a style trigger but I imagine it would be the same principle.
<TreeView>
<TreeView.ContextMenu>
<ContextMenu>
<StaticResourceExtension ResourceKey="myMenuItem"></StaticResourceExtension>
</ContextMenu>
</TreeView.ContextMenu>
</TreeView>

MenuItem Vertical alignment issue

I am facing an issue with MenuItem that whenever I specify an access key, the header alignment is getting disrupted. Below is a sample image wherein I have specified "_New" for New menu item and bound it to New command. You can observe tha the Text "New" is align at bottom and shortcut key is aligned at top. Also for other menu items I have not specified any access key, so they have no issue.
Here is the XAML
<StackPanel DockPanel.Dock="Top">
<Menu Padding="0,5">
<MenuItem x:Name="MnuTask" Header="Task">
<MenuItem x:Name="MnuNew" Header="_New" Command="New"/>
<MenuItem x:Name="MnuSave" Header="Save" Command="Save"/>
<MenuItem x:Name="MnuDelete" Header="Delete" Command="Delete"/>
<Separator/>
<MenuItem x:Name="MnuRefresh" Header="Reload Data" Command="{x:Static Local:MainWindow.RefreshDataCommand}" />
<MenuItem x:Name="MnuHistory" Header="View Range History" Command="{x:Static Local:MainWindow.RangeHistoryCommand}" />
<Separator/>
<MenuItem x:Name="MnuExit" Header="Exit" Command="Close"/>
</MenuItem>
<MenuItem x:Name="MnuView" Header="View">
<MenuItem x:Name="MnuFind" Header="Find Formula"/>
</MenuItem>
</Menu>
</StackPanel>
Could any body let me know what's going on?
Found it. I had the below TextBlock Style present in Resources section of my window. Commenting those lines resolved the issue. (But now I need to apply TextBlock style explicitly using keys :( )
<Style TargetType="TextBlock">
<Setter Property="Margin" Value="3,6,3,0"/>
<Setter Property="VerticalAlignment" Value="Bottom"/>
</Style>

Categories

Resources