Enable/Disable Textblock in a ContextMenu - c#

I have a ContextMenu with a MenuItem inside it. The MenuItem is a TextBlock as shown in the below code:
<ContextMenu>
<Border>
<MenuItem>
<MenuItem.Header>
<TextBlock Text="ACK" HorizontalAlignment="Right"/>
</MenuItem.Header>
</MenuItem>
</Border>
</ContextMenu>
How do I enable or disable it at runtime. If I click it once, it should be disabled.
PS: I don't want to write code-behind for this. I need to achieve it from the XAML as this is done in a UserControl and is going to be used in many applications.

Related

WPF shared menu between main top menu and right click context menu

I'm trying to make a shared menu between something on my top menu bar of my app, and the right click context menu of something in my interface in WPF. I've googled aroudn but I can't figure out hwo to share ONLY the menuitems list.
Here is a picture of the UI to help describe it:
The way this works is when an item in the list (as shown in the background) is selected, this menu becomes available to use. I would like to make it so that when you right click an item in the list, it also shows the same menu. I would like to avoid duplicating code, so I defined a resource for MenuItem in my window resources:
<MenuItem x:Key="modUtilsMenu">
<MenuItem Header="{Binding SelectedMod.ModName}" IsEnabled="False" FontWeight="Bold" />
<MenuItem Header="{DynamicResource string_Checkforupdates}" Command="{Binding SelectedModCheckForUpdatesCommand}" ToolTip="{DynamicResource string_tooltip_checksForUpdatesToThisMod}" >
<MenuItem.Icon>
<fa:ImageAwesome Style="{StaticResource EnableDisableImageStyle}" Icon="Cloud" Foreground="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Height="16" Width="16"/>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="{DynamicResource string_RestoremodfromME3Tweaks}" Command="{Binding RestoreModFromME3TweaksCommand}" ToolTip="{DynamicResource string_tooltip_forcesUpdateCheck}" >
<MenuItem.Icon>
<fa:ImageAwesome Style="{StaticResource EnableDisableImageStyle}" Icon="CloudDownload" Foreground="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Height="16" Width="16" RenderOptions.BitmapScalingMode="HighQuality"/>
</MenuItem.Icon>
</MenuItem>
...
I then add it to the interface as a sub element of the Mod Utils menuitem:
<MenuItem Header="{DynamicResource string_ModUtils}" Padding="4" IsEnabled="{Binding SelectedMod, Converter={StaticResource NullEnabledConverter}}">
<StaticResource ResourceKey="modUtilsMenu"/>
</MenuItem>
Obviously this doesn't work as it has a second MenuItem defined in the resource.
However, I am not sure how I can store a "list" of menu items to add as children of another object, as the root container element of MenuItem and ContextMenu are not the same. These are all command based menu items. I will have the same issue with a context menu too - how do I only share the contents and not the container? Do I have to do data binding?
I have looked at How do I share a menu definition between a context menu and a regular menu in WPF, but that seems to be just for single menu items. I suppose I could do it for every one of them, but I'm looking to see if there's a way to do this where I only have to update it in one place instead of three to make it work.
Menu and ContextMenu are both of type ItemsControl. You can treat them like this e.g. bind to a collection of item models and specify a DataTemplate.
The following example creates a collection of MenuItem as XAML resource.
To allow multiple instances of the collection it is important to to set the x:Shared attribute to False. Otherwise the menu will be rendered only in one location of the visual tree, no matter the number of references:
<Window>
<Window.Resources>
<x:Array x:Key="SharedMenuItems"
Type="MenuItem"
x:Shared="False">
<MenuItem Header="File">
<MenuItem Header="Save" />
</MenuItem>
<MenuItem Header="Settings" />
</x:Array>
</Window.Resources>
<StackPanel x:Name="RootPanel" viewModels:Item.IsMarkedAsRead="True">
<Menu ItemsSource="{StaticResource SharedMenuItems}" />
<Grid>
<Grid.ContextMenu>
<ContextMenu ItemsSource="{StaticResource SharedMenuItems}" />
</Grid.ContextMenu>
</Grid>
</StackPanel>
</Window>

How do I prevent a ToolBar in a nested UserControl from being focused when switching tabs?

I wrote an example application that highlights the issue, which might have to do with focus-scope because it's whenever a ToolBar is involved and a UserControl is unloaded when switching tabs.
The main window contains a Menu with a File->New command and a TabControl that displays a collection of "Box" instances:
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_File">
<MenuItem Command="New"/>
</MenuItem>
</Menu>
<TabControl ItemsSource="{Binding Boxes}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" Width="40"/>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<local:BoxView/>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</DockPanel>
Each "Box" instance has a Name property displayed in the tab header, and the rest of it is displayed in a "BoxView" UserControl. The "BoxView" has a ToolBar, the first button of which becomes the focus hog in the mentioned use case. The "BoxView" also displays a collection of "Compartments" that are inside each "Box" instance:
<StackPanel>
<ToolBarTray IsLocked="True">
<ToolBar>
<Button Content="Focus hog"/>
</ToolBar>
</ToolBarTray>
<ItemsControl ItemsSource="{Binding Compartments}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:CompartmentView/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
Each "Compartment" instance has a TotalValue property simply displayed in a TextBox in a "CompartmentView" UserControl:
<StackPanel>
<TextBox Text="{Binding TotalValue}"/>
</StackPanel>
And the problem is...
If I click on the TextBox of any one of the CompartmentView's, and then click a different tab of the main window, the first button of the ToolBar of the BoxView is focused (the focus hog one), disabling commands working in the main window.
It can be observed commands are disabled when opening the File menu. But after closing the menu and reopening, commands are enabled again.
How do I prevent the ToolBar in the nested UserControl from being focused when switching tabs?
Or perhaps I'm going at this wrong... how do I prevent focus from being set when switching tabs?
Update
The following link is a video on youtube where I explain the problem with the application.
https://youtu.be/0T5LK3CYxgw
Solution update
Thanks to themightylc for the answer, the issue was clearly a keyboard focus problem when the focused visual control (any selected "CompartmentView" or "BoxView" control) was unloaded while changing the selected tab in the TabControl. The solution was to focus on the TabControl itself in the main window whenever the tab selection changed:
private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
(sender as TabControl).Focus();
}
Thanks also to Christoph Nahr's response for the solution on this msdn thread: https://social.msdn.microsoft.com/Forums/vstudio/en-US/f5de6ffc-fa03-4f08-87e9-77bbad752033/a-focusscope-nightmare-bug-commands-are-disabled?forum=wpf
<Button Content="Focus hog" Focusable="False" />
This solves the problem you're having. Focusable is a DependencyProperty If you still want to access the ToolBar via Keyboard-Focus, you can bind it or set it from code-behind when the Tab-Switch is complete.
You can of course set it via Style so you don't have to set it on every element of the ToolBar.

How can add key shortcut on the MenuItem header wpf xaml

I try to search on internet but I not find anything. I want to show on the user when is click on the menu in menuitem what is the shortcut for this command (menuitem).
For example I want to make like "Build Solution" and is can see what shortcut is have.
Here is my xaml what I try:
<MenuItem Name="HelpMenuItem" HorizontalContentAlignment="Center" MouseLeave="HelpButtonMouseLeave" MouseEnter="HelpButtonMouseEnter" Header="{catel:LanguageBinding ResourceName=HelpSubMenu}" Command="{Binding Help}">
<MenuItem.InputBindings>
<KeyBinding Key="F1" Gesture="F1" Modifiers="Control" Command="Help" />
</MenuItem.InputBindings>
</MenuItem>
Is it possible to make it only with xaml
You can use InputGestureText property of the MenuItem. According to MSDN it designed exactly for this purporse (https://msdn.microsoft.com/ru-ru/library/system.windows.controls.menuitem.inputgesturetext%28v=vs.110%29.aspx).
<MenuItem Name="HelpMenuItem" Header="Help" InputGestureText="F1" />
Edit
Unfortunately it's not works for root MenuItems. For this case you can write something like this.
<MenuItem>
<MenuItem.Header>
<DockPanel>
<TextBlock Text="Help" Margin="0,0,10,0" />
<TextBlock Text="Ctrl+F1" />
</DockPanel>
</MenuItem.Header>
</MenuItem>

Disabled menu element in WPF looks enabled

My problem is twofold, but i guess that they are related, and if I manage to fix one of them, I will solve both.
First of, lets see the xaml code for a ContextMenu that is linked to a Caliburn.Micro view model:
<ContextMenu>
<MenuItem Header="Configure modem" ItemsSource="{Binding Modems}">
<MenuItem.ItemTemplate>
<DataTemplate>
<MenuItem>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ca:ActionMessage MethodName="SelectModem">
<ca:Parameter Value="{Binding Path=DataContext, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}" />
</ca:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>
<MenuItem.Header>
<DockPanel>
<Image DockPanel.Dock="Left" Source="{Binding CarrierProfile.CarrierProfileIcon}" Width="40" Height="40"/>
<TextBlock Text="{Binding MenuText}" VerticalAlignment="Center" Margin="10 0"/>
</DockPanel>
</MenuItem.Header>
</MenuItem>
</DataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
</ContextMenu>
So basically this is just a DataTemplate where I set the Header to a DockPanel containing an image and a TextBlock.
One MenuItem looks like this:
Here you can see the main problem. You can see that there are "two selections". One outer selection, and one inner. If I click the inner selection, everything is fine, and my SelectModem method is called from my view model. However, if you click the outer selection the context menu goes away so that user thinks he has made a selection, but actually no method is called on the view model.
My second problem is that if I disable the MenuItem by adding IsEnabled="False" in the code above, the menu item looks disabled (text is grayed out), I cannot make the inner selection, but on hover is still shows the outer selection, and when clicked the menu goes away (but nothing is triggered in my view model)
So the question is: How can I get rid of the the outer selection?

Checkbox inside context menu not displays correctly wp7

I have a context menu and checkbox inside it, but checkbox displays not correctly.
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu >
<toolkit:MenuItem Click="iLikeIt" Tag="{Binding ElementName=chbox}" Header="{Binding isLikeMe, Converter={StaticResource LikeIt}}"/>
<toolkit:MenuItem>
<toolkit:MenuItem.Header>
<CheckBox Name="chbox" Tag="{Binding}" BorderThickness="1" Content="Рассказать друзьям" >
</CheckBox>
</toolkit:MenuItem.Header>
</toolkit:MenuItem>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
As this is a UI issue and not a functional one this is very likely a styling issue with the CheckBox. You will need to apply a custom style to the CheckBox in the ContextMenu so that it looks OK in the inverted colours of the ContextMenu.
Make sure you make it work in both Dark and Light theme though.

Categories