ygoe
ygoe

Reputation: 20394

Disable underscore interpretation for MenuItems

There's a menu in my application that gets its contents directly from an externally bound list of strings (ItemsSource = Settings.RecentlyLoadedFiles). These strings are file names and when the user clicks on an item in the menu, that file shall be loaded.

<ui:SplitButton
    Grid.Column="0"
    Command="{Binding LoadLogCommand}" ToolTip="Load log" ToolTipService.ShowOnDisabled="True"
    Focusable="False"
    ItemsSource="{Binding Settings.RecentlyLoadedFiles}"
    MenuItem.Click="SplitButton_Click">
    <ui:SplitButton.Icon>
        <ui:MenuIconImage Source="/Images/folder_open.png"/>
    </ui:SplitButton.Icon>
</ui:SplitButton>

Now file names can easily have an underscore in them and this isn't displayed because WPF thinks it might be an accelerator key. It's not. But how can I tell that to the menu?

There's no easy way to double those underscores to have one of them displayed. The list comes from a source that has nothing to do with such things.

Do I need to write a custom converter to convert that list into a list of strings with doubled underscores only to disable that feature?

Or do I need to copy the entire template for the menu items from somewhere to set one specific property differently somewhere in the middle of it?

Isn't there some attached property or anything that propagates down to where that interpretation would be done?

Upvotes: 3

Views: 1838

Answers (2)

Mark Feldman
Mark Feldman

Reputation: 16128

Use a converter. If you're not using bindings then you can pass the value in via the CommandParameter, here's how you would do it in XAML:

    <Menu DockPanel.Dock="Top">
        <Menu.Resources>
            <converters:MenuTextConverter x:Key="MenuTextConverter" />
        </Menu.Resources>
        <MenuItem Header="{Binding Converter={StaticResource MenuTextConverter}, ConverterParameter='_File'}" />
        <MenuItem Header="{Binding Converter={StaticResource MenuTextConverter}, ConverterParameter='_Edit'}" />
    </Menu>

And here's how you would do it in code-behind:

        InitializeComponent(); // do this first

        var menuItem1 = new MenuItem();
        var binding1 = new Binding();
        binding1.Converter = converter;
        binding1.ConverterParameter = "_File";
        BindingOperations.SetBinding(menuItem1, MenuItem.HeaderProperty, binding1);
        this.theMenu.Items.Add(menuItem1);

        var menuItem2 = new MenuItem();
        var binding2 = new Binding();
        binding2.Converter = converter;
        binding2.ConverterParameter = "_Edit";
        BindingOperations.SetBinding(menuItem2, MenuItem.HeaderProperty, binding2);
        this.theMenu.Items.Add(menuItem2);

Here's code for the converter itself:

public class MenuTextConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return parameter.ToString().Replace("_", "__");
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

If you're passing in the menuitem strings via the binding itself then obviously you'd just change the converter to use value instead of parameter.

Upvotes: 3

Kory Gill
Kory Gill

Reputation: 7163

If you can't (or don't want to) double the underscores and use a new list, you can also not add the strings directly to the menu, but rather put each one in a TextBlock and add the TextBlocks to the menu.

This snippet demonstrates both techniques working as expected without accelerators on the 2nd and 3rd ones.

var s = "_UnderScore";
var mi = new MenuItem();
mi.Header = s;
myMenu.Items.Add(mi);

var d = "__UnderScore";
mi = new MenuItem();
mi.Header = d;
myMenu.Items.Add(mi);

var t = new TextBlock();
t.Text = s;
mi = new MenuItem();
mi.Header = t;
myMenu.Items.Add(mi);

Personally, I usually avoid adding any strings directly to things like menus because invariably, the next thing you want to do is extend the solution to add icons for the file type, show a tooltip on hover, etc. which takes you down the path of using a control or something to "host" each menu item.

Upvotes: 1

Related Questions