TextBlock inside MenuItem does not became gray if MenuItem is Disabled - wpf

If I use this code:
<MenuItem x:Name="MenuSave" Header="Save" IsEnabled="False"/>
when MenuSave is disabled (in real code by a RoutedUICommand programmatically), the Header is disabled and text is gray.
But if I need more text like here:
<MenuItem x:Name="MenuSaveAs" IsEnabled="False">
<MenuItem.Header >
<StackPanel Orientation="Horizontal">
<TextBlock Text="Save as"/>
<TextBlock> ...</TextBlock>
</StackPanel>
</MenuItem.Header>
</MenuItem>
In this case, the Header is disabled but text is not gray.
How can I obtain text gray with composite text?
This is just simplified code to explain the problem, the real code is combination of translated terms.

If you add the TextBlock thorough a HeaderTemplate, the color will be applied for the disabled state. By the way, you can use multiple Runs instead, so the same TextBlock is populated. If you bind a data item as Header, you can bind its properties in the template to the Runs.
<MenuItem x:Name="MenuSaveAs" IsEnabled="False">
<MenuItem.HeaderTemplate>
<DataTemplate>
<TextBlock>
<Run Text="Save as"/>
<Run> ...</Run>
</TextBlock>
</DataTemplate>
</MenuItem.HeaderTemplate>
</MenuItem>
Alternatively, if you need to format a string with a bound property, use HeaderStringFormat.
<MenuItem x:Name="MenuSaveAs"
IsEnabled="False"
Header="{Binding NameOfTheSavedItem}"
HeaderStringFormat="Save as {0}...">
If you really insist on setting the header directly, a workaround would be to bind the Foreground of TextBlock explicitly to the TextElement.Foreground of the ContentPresenter in the MenuItem control template. You can bind it on each TextBlock or add an implicit style that applies to all TextBlocks in scope automatically. Please note the word all.
<Menu>
<Menu.Resources>
<Style TargetType="TextBlock" BasedOn="{StaticResource {x:Type TextBlock}}">
<Setter Property="Foreground" Value="{Binding (TextElement.Foreground), RelativeSource={RelativeSource AncestorType=ContentPresenter}}"/>
</Style>
</Menu.Resources>
<MenuItem x:Name="MenuSaveAs"
IsEnabled="True">
<MenuItem.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Padding="0" Text="Save as"/>
<TextBlock Padding="0" Text="..."/>
</StackPanel>
</MenuItem.Header>
</MenuItem>
</Menu>
Please be aware that I suggest to use a single TextBlock with Runs for sentences or paragraphs in general, because panels with multiple TextBlocks result in incorrect spacing and alignment that do not match the typesetting that TextBlock and other document related types provide. It usually looks odd and disjointed and does not take into account the characteristics of a font.

I found an other easy way using <Label Padding="0"..>, instead af <TextBlock ..>:
<MenuItem x:Name="MenuSaveAs" IsEnabled="False">
<MenuItem.Header >
<StackPanel Orientation="Horizontal">
<Label Padding="0" Content="Save as"/>
<Label Padding="0" Content="..."/>
</StackPanel>
</MenuItem.Header>

Related

MenuItem within MenuItem not using all available space

I have a menuitem that contains a datatemplate of a menuitem. Problem is the menuitem within that is not taking up all the available space on the right. Is there any way I can fix this?
<MenuItem Header="Test" ItemsSource="{Binding DataContext.Test, Source={x:Reference TestControl}}"
Command="{Binding DataContext.Test_Click, Source={x:Reference TestControl}}">
<MenuItem.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding TestName}"
Command="{Binding DataContext.Test_Click, Source={x:Reference TestControl}}"
CommandParameter="{Binding TestId}">
<MenuItem.Icon>
<Ellipse Fill="{Binding TestId, Converter={StaticResource TestConverter}}"/>
</MenuItem.Icon>
</MenuItem>
</DataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
What you are observing is the built-in column spacing of the default MenuItem's ControlTemplate.
Highlighting the culprit below:
These column definitions are used to show any keyboard shortcuts that you may have for the menu item, as well as some hardcoded column padding of 13 (why? I have no idea).
So to answer your question, if you want to take up the available space on the right, you will need to override the MenuItem's Template with a ControlTemplate of your own that does not include these last two column definitions.

How to get menu items command CanExecute to apply when using images and text

If I convert my menu code from:
<MenuItem Header="Remove Special Event"
Command="{Binding RemoveSpecialEventCommand, Mode=OneWay}" />
To:
<MenuItem Command="{Binding RemoveSpecialEventCommand, Mode=OneWay}">
<MenuItem.Header>
<StackPanel Orientation="Horizontal">
<Image Source="Images/RemoveSpecialEvent.png" Stretch="None" Margin="0,0,5,0"/>
<TextBlock>Remove Special Event</TextBlock>
</StackPanel>
</MenuItem.Header>
</MenuItem>
Now the Command CanExecute is not being applied to the menu item. They are all enabled.
Update
I don't particularly expect this to work.
It worked!
I can't reproduce your issue, and I'm going to take you at your word that it's absolutely disabled, but yet does not gray out the text. I suppose it might be a theme thing.
Here's one thing you can try: Instead of giving the Header property a visual tree fragment, try templating the plain string header content instead.
<MenuItem
Header="Remove Special Event"
Command="{Binding RemoveSpecialEventCommand, Mode=OneWay}"
>
<MenuItem.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image
Source="Images/RemoveSpecialEvent.png"
Stretch="None"
Margin="0,0,5,0"
/>
<ContentControl
Content="{Binding}"
/>
</StackPanel>
</DataTemplate>
</MenuItem.HeaderTemplate>
</MenuItem>
I don't particularly expect this to work.

Should I use a ContextMenu to show a couple of buttons?

I am developing a WPF application and I want the following functionality: If a user right clicks on a progress bar a small context menu should popup at the clicked position. This menu should just contain a couple of buttons which are lined up horizontally. Should I use the ContextMenu for this or are there better suitable WPF elements?
I tried a ContextMenu and this is how it looks like:
This is the XAML:
<ProgressBar x:Name="PgF" Height="10" Value="{Binding Path=FileCurrentMs}" Maximum="{Binding Path=FileLengthMs}">
<ProgressBar.ContextMenu>
<ContextMenu>
<StackPanel Orientation="Horizontal">
<Button Content="A"/>
<Button Content="B"/>
<Button Content="C"/>
</StackPanel>
</ContextMenu>
</ProgressBar.ContextMenu>
</ProgressBar>
In the ContextMenu I have the space to the left and to the right which I don’t want and I read in other posts that it is not simple just to remove this space. Any ideas?
Try like this :
<ProgressBar x:Name="PgF" Height="10" Value="{Binding Path=FileCurrentMs}" Maximum="{Binding Path=FileLengthMs}">
<ProgressBar.ContextMenu>
<ContextMenu>
<MenuItem>
<MenuItem.Template>
<ControlTemplate>
<StackPanel Orientation="Horizontal">
<Button Content="A" Margin="2"/>
<Button Content="B" Margin="2"/>
<Button Content="C" Margin="2"/>
</StackPanel>
</ControlTemplate>
</MenuItem.Template>
</MenuItem>
</ContextMenu>
</ProgressBar.ContextMenu>
</ProgressBar>
You need to put all buttons in a single menu item :) good luck

Contextmenu on listview datatemplate not working

I have a simple ListView bound to a collection of Calculations. The view calls the calc Name property in the display. I have set the contextmenu to the individual items in the listview but on right click the context menu shows up as a tiny box with nothing in. What am i missing?
<ListView x:Name="CalcList" ItemsSource="{Binding Calculations}">
<ListView.ItemTemplate>
<DataTemplate DataType="x:Type lib:Calculation">
<DataTemplate.Resources>
<ContextMenu x:Key="CalcMenu">
<MenuItem Header="Delete Calculation" Click="MenuItem_Click"/>
<MenuItem Header="Another"/>
<MenuItem Header="Another"/>
</ContextMenu>
</DataTemplate.Resources>
<Border BorderBrush="Black" BorderThickness="1" Margin="2">
<Border.ContextMenu>
<ContextMenu ContextMenu="{StaticResource CalcMenu}"/>
</Border.ContextMenu>
<TextBlock MouseLeftButtonDown="DisplayCalc" Text="{Binding Path=Name}"></TextBlock>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Thanks.
If anything, you have a syntax error the way you define the Border.ContextMenu element. The correct syntax (of the Border Element):
<Border BorderBrush="Black" BorderThickness="1"
Margin="2"
ContextMenu="{StaticResource CalcMenu}">
<TextBlock ... />
</Border>
Saying that, there is a lot of optimization you can do. First, instead of instantiating a context menu for each item, you can move the CalcMenu to the section (one level up), or even farther up - to the main window.
Second, why do you define a separate context menu for each item? Is it really important context menu won't popu when mouse is in the margin between items? simply set the context menu to the entire list:
<ListView x:Name="CalcList" ContextMenu="{StaticResource CalcMenu}">
...
and define the CalcMenu as a main window resources, or inline the ListView element (not a static resource).

Change Color of Single Letter in Label String?

I have a project in WPF 4 and VB.net. I need to change the color a single letter in a word in a label (the label's content changes quite a bit). I really am not sure if this is possible, but if it is, I'd appreciate help on figuring out how. TY!
Label is a content control so any type of content is permitted inside a label.You can easily do your requirement by something like
<Label>
<StackPanel Orientation="Horizontal">
<TextBlock Foreground="Red" Text="T"/>
<TextBlock Text="ext"/>
</StackPanel>
</Label>
A cleaner way would be using the flow-content-capabilites of a TextBlock:
<Label>
<TextBlock>
<Run Text="L" Foreground="Green"/>
<Run Text="orem Ipsum"/>
</TextBlock>
</Label>
This limits binding a bit though, if that is needed.
The cleanest method i found so far is using a TextEffect:
<Label>
<TextBlock Text="Search">
<TextBlock.TextEffects>
<TextEffect PositionStart="0" PositionCount="1" Foreground="Red"/>
</TextBlock.TextEffects>
</TextBlock>
</Label>
This colors the "S" red. You can of course bind any of the involved properties if they need to be dynamic.
I just implemented something like this in our project, this will be static though - I'm not sure if that's what you need. You can change the content of the label as often as you need, but it will always have a red * at the end. I added a style to the project like this
<Style x:Key="RequiredFieldLabel"
TargetType="{x:Type Label}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}" />
<TextBlock Text="*"
Foreground="red" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
Then you can use this style on a label anywhere in your project.
<Label Content="Enter Name:"
Style="{StaticResource RequiredFieldLabel}" />

Resources