Databinding with DisplayMemberPath escapes underscore in menuitem - c#

Ok, so we have a recent file menu option. We databind the MenuItem entries using MVVM and supply the DisplayMemberPath. But WPF escapes the string so underscore is displayed as an underscore instead as the accesskey
<MenuItem x:Name="RecentScripts" DisplayMemberPath="Caption" Header="Recent _Files" cal:Message.Attach="OpenRecentScript($orignalsourcecontext)">
<MenuItem.Icon>
<Image Source="{StaticResource IconOpen}"/>
</MenuItem.Icon>
</MenuItem>
https://github.com/AndersMalmgren/FreePIE/blob/recet_files_shortcut/FreePIE.GUI/Views/Main/Menu/MainMenuView.xaml#L35
We also have custom theme, but disabling style for MennuItem does not help
https://github.com/AndersMalmgren/FreePIE/blob/recet_files_shortcut/FreePIE.GUI/Themes/ExpressionDark.xaml#L1921

Replace the DisplayMemberPath with ItemTemplate. Like explained here DisplayMemeberPath is
a template for a single property, shown in a TextBlock
As #XAMlMAX mentioned TextBlock doesn't support AccessText, while Label does.
<MenuItem x:Name="RecentScripts" Header="Recent _Files" cal:Message.Attach="OpenRecentScript($orignalsourcecontext)">
<MenuItem.Icon>
<Image Source="{StaticResource IconOpen}"/>
</MenuItem.Icon>
<MenuItem.ItemTemplate>
<DataTemplate>
<Label Content="{Binding Caption}"/>
</DataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>

Related

How to show context menu on a ListBoxItem template on a grid when right-clicking outside the contents of it?

Hello,
I have a ListBox.ItemTemplate (containing obviously a DataTemplate) containing a Grid which itself contains a Label.
The Grid has a Grid.ContextMenu. The issue is that the ContextMenu only shows when I right click on the Label. Not outside.
Here is an image to show the problem if you didn't understand (But I am sure you did ;) !)
Here is the code :
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="0,0,0,1">
<Grid.ContextMenu>
<ContextMenu>
<MenuItem CommandParameter="{Binding}" Command="{Binding Source={x:Reference window}, Path=DataContext.DeleteCommand}" Header="Supprimer">
<MenuItem.Icon>
<Image Source="/SchoolTools.Teacher;component/Images/DeleteIcon.png" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</Grid.ContextMenu>
<Label Content="{Binding ClassYear}" Padding="0"
HorizontalAlignment="Center" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
Thanks !
Change the label's HorizontalAlignment to Stretch so that it fills the entire grid cell.

MenuItem command called when clicking IsCheckable checkbox

My XAML:
<MenuItem Command="{Binding ShowRequestsCommand}" HorizontalAlignment="Stretch" IsCheckable="True" IsChecked="{Binding ShowUrgentEvaluationRequestNotification, Source={x:Static Properties:Settings.Default}, Mode=TwoWay}">
<MenuItem.Header>
<StackPanel Orientation="Horizontal">
<Border Background="Red" CornerRadius="5" Padding="3,1,3,1" Margin="1,1,5,1" HorizontalAlignment="Left" MinWidth="18"></Border>
<TextBlock>Beställningshanteraren</TextBlock>
</StackPanel>
</MenuItem.Header>
</MenuItem>
So it's a MenuItem with some stuff in the header, it is checkable, and that value is supposed to have some functionality elsewhere, it also has a command.
My problem is that when you click the checkbox, the command is called, which is not my intention, and it seems wrong for any situation honestly. You should be able to click the checkbox without activating whatever the MenuItem is supposed do do. I get the same result if I add a click event on the menuitem instead.
Why does WPF work like this? Is there a workaround?

How to bind command into ContextMenu in DataTemplate

I'm a little bit lost with bindings.
I tried so many things in the last hour, I cannot enumerate all of them. I have an issue with a contextMenu inside a DataTemplate.
To explain: I have a UserControl. Its dataContext is itself. Inside this UserControl, I have an ItemsControl to represent a list of Hyperlink. My ItemsControl itemsSource is bound (it is composed of objects elements).
I redefined ItemsControl.ItemTemplate. Inside, I create a HyperLink, with TextBlock as child to make it work, and on this TextBlock, I set a ContextMenu by doing the following.
<TextBlock.ContextMenu>
<ContextMenu DataContext="{Binding PlacementTarget, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Enregistrer la pièce jointe" Foreground="Black">
<MenuItem Header="Dans le dossier patient" Command="{Binding DataContext.SaveAttachmentIntPatientFolderCommand, RelativeSource={RelativeSource AncestorType=UserControl}}" CommandParameter="{Binding FilePath}" Foreground="Black" />
<MenuItem Header="Enregistrer sous ..." Command="{Binding DataContext.SaveAttachmentAsCommand}" CommandParameter="{Binding FilePath}" Foreground="Black" />
</MenuItem>
</ContextMenu>
</TextBlock.ContextMenu>
So I have
UserControl --> ItemsControl --> ItemTemplate --> HyperLink --> TextBlock --> ContextMenu --> ContextMenuItem
I know that my first relative source doesn't work, I have a binding error. What I want is to bind on my UserContorl datacontext, which have these commands.
How can I proceed?
Thanks
ContextMenu takes the DataContext of the ItemsControl and so it cannot access the ViewModel directly. Also It is not part of the VisualTree and so you cannot do RelativeSource binding. So We need to get the DataContext of the UserControl through TextBlock's Tag property and then bind to ContextMenu.
You refer the below code.
<TextBlock Text="{Binding }" Tag="{Binding DataContext, RelativeSource={RelativeSource AncestorType=UserControl}}">
<TextBlock.ContextMenu>
<ContextMenu >
<MenuItem Header="Enregistrer la pièce jointe" Foreground="Black">
<MenuItem Header="Dans le dossier patient"
Command="{Binding Path=PlacementTarget.Tag.SaveAttachmentIntPatientFolderCommand,
RelativeSource={RelativeSource AncestorType=ContextMenu}}"
Foreground="Black" />
<MenuItem Header="Enregistrer sous ..."
Command="{Binding Path=PlacementTarget.Tag.SaveAttachmentAsCommand,
RelativeSource={RelativeSource AncestorType=ContextMenu}}"
Foreground="Black" />
</MenuItem>
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>

WPF binding command to ContextMenu

I have a problem with command binding in WPF. I have the following xaml:
<ItemsControl ItemsSource="{Binding Entity}" Name="Lst">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Button Content="qwerty" Command="{Binding ElementName=Lst, Path=DataContext.SaveCommand}" >
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="Send2" Command="{Binding ElementName=Lst, Path=DataContext.SaveCommand}" />
</ContextMenu>
</Button.ContextMenu>
</Button>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
As you can see Button and its ContextMenu have the similar command-bindings. But when i click button its command is firing and when i click context menu's item its command isn't firing. Where am i wrong? Thanks in advance!
I had a similar problem before and solved it by passing the datacontext through the tag property of the container as below. I have it working on a grid ContextMenu but dont see any reason why this wont work on a button. Let me know if you have any problem
<Button Content="qwerty" Tag="{Binding DataContext,ElementName=Lst}" Command="{Binding ElementName=Lst, Path=DataContext.SaveCommand}" >
<Button.ContextMenu>
<ContextMenu DataContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Send2" Command="{Binding SaveCommand}" />
</ContextMenu>
</Button.ContextMenu>
</Button>
The ContextMenu being separate from the visual tree, you cannot bind with and element outside of it.
If you check your output window, you should have a message saying that it can't find the object "Lst"
A common and easy workaround would be to manually set the DataContext in code-behind (note: this is not breaking MVVM at all. You are just performing a pure UI operation of linking DataContexts together):
In your Xaml:
<Button.ContextMenu>
<ContextMenu Opened="OnContextMenuOpened">
<MenuItem Header="Send2" Command="{Binding ElementName=Lst, Path=DataContext.SaveCommand}" />
</ContextMenu>
</Button.ContextMenu>
In code-behind:
public void OnContextMenuOpened(object sender, RoutedEventArgs args)
{
(sender as ContextMenu).DataContext = Lst.DataContext;
}
You are therefore linking the DataContext every time the ContextMenu is opened (so if Lst's DataContext changes, your ContextMenu will as well)
Alternatively (cleaner if you are bound to use it a lot of times), get the BindingProxy from this article: http://tomlev2.wordpress.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/ and it'll do the trick!

Show menu entries only for certain user roles

I'd like to get to know how I can set menu entries visible or hidden for certain user roles in XAML code? Eg I have "_MenuEntryForADMIN" which should only visible for user role "admin" and "_MenuEntryForAllUsers" should be visible to all users - role "user".
Here is my XAML code:
<Grid>
<DockPanel>
<MenuItem Header="_MenuEntryForADMIN">
<MenuItem Header="_Master1" Click="btnMaster1_Click">
<MenuItem.Icon>
<Image Source="database.png" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="_Master2" Click="btnMaster2_Click">
<MenuItem.Icon>
<Image Source="database.png" />
</MenuItem.Icon>
</MenuItem>
</MenuItem>
<MenuItem Header="_MenuEntryForAllUsers">
<MenuItem Header="_Normal1" Click="btnNormal1_Click">
<MenuItem.Icon>
<Image Source="database.png" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="_Normal2" Click="btnNormal2_Click">
<MenuItem.Icon>
<Image Source="database.png" />
</MenuItem.Icon>
</MenuItem>
</MenuItem>
</Menu>
</DockPanel>
</Grid>
The CS-Code contains the information whether a user has the role "admin" or "user" like this:
User userObject;
public MainWindow(User userObject)
{
InitializeComponent();
this.userObject = userObject; // this.userObject.Role is "admin" or "user"
}
In WPF, it is important to 'shape' your data into the correct structure before you try to display it. By this, I mean that you should filter the data, your MenuItems, in your view model or code behind before displaying them, rather than trying to filter them in the UI.
So rather than defining them all in XAML, create some custom data type to data bind to the various MenuItem properties that you are interested in. Then create a DataTemplate and bind a collection of these to the MenuItem.ItemsSource property. You can find out how to do that from my answer to the Dynamically hiding menu items question. In short, it looks something like this:
<DataTemplate x:Key="MenuItemTemplate" DataType="{x:Type MenuItem}">
<MenuItem Command="{Binding Command}" CommandParameter="{Binding CommandParameter}"
Header="{Binding Path=Header}" Visibility="{Binding Visible, Converter={
BooleanToVisibilityConverter}}" ItemsSource="{Binding ChildMenuItems}" />
</DataTemplate>
There are also many examples online of filtering data in collections, so I won't go over all of that here. You can find a short example in the “Hiding” part of List question here on Stack Overflow. Basically, you can use LinQ to select just the admin MenuItems something like this:
ChildMenuItems = new ObservableCollection<YourCustomDataType>(
FullCollection.Where(i = i.Role == "admin").ToList());

Categories

Resources