19

I'm coming from WinForms and teaching myself WPF for the first time.
I thought I'd start by recreating the interface of one of my WinForms apps in WPF but I'm having an issue already with the menu.

I can't figure out why the menus in the WPF application open right to left, when the menus on the WinForms app open left to right (which is what I want):

enter image description here

It's a practically empty project with just the default settings. Here's the XAML:

<Window x:Class="WpfTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Test" Height="541.771" Width="828.947" WindowStartupLocation="CenterScreen">
    <DockPanel LastChildFill="False" Margin="0" Background="#FFFDFD9C">
        <Menu x:Name="menu" Height="22" VerticalAlignment="Top" RenderTransformOrigin="1.79,0.076" DockPanel.Dock="Top" Margin="0">
            <MenuItem Header="File">
                <MenuItem Header="New Document"/>
                <MenuItem Header="Open Template"/>
                <MenuItem Header="Open Collateral"/>
                <Separator/>
                <MenuItem Header="Synchronise"/>
                <Separator/>
                <MenuItem Header="Build Document"/>
                <MenuItem Header="Document History">
                    <MenuItem Header="Load Last Document"/>
                </MenuItem>
                <Separator/>
                <MenuItem Header="Settings"/>
                <Separator/>
                <MenuItem Header="Exit"/>
            </MenuItem>
            <MenuItem Header="Help">
                <MenuItem Header="User Guide"/>
                <MenuItem Header="About"/>
            </MenuItem>
        </Menu>
        <Rectangle Fill="#FFB8B8FF" Height="80" VerticalAlignment="Top" DockPanel.Dock="Top" Margin="0"/>
    </DockPanel>
</Window>

What am I missing?

Equalsk
  • 7,954
  • 2
  • 41
  • 67
  • 1
    All I can think of is a culture on your PC might be messing things up, try setting `FlowDirection="LeftToRight"` in your Window? Also if the Window is to the very right edge of the screen it will pop up on the other side. – XAMlMAX May 19 '16 at 14:47
  • My culture is en-GB. FlowDirection didn't seem to make a difference. I added it within the `` tag, I assume this was correct? It's not at the very right of the screen, there's plenty of room for the menu to open. – Equalsk May 19 '16 at 14:49
  • Do you need that `RenderTransform` in your Menu ? Or are you using designer to drag and drop things on screen? – XAMlMAX May 19 '16 at 14:54
  • I've used the designer to drag items onto the form. The property was added automatically and I don't understand what it does so I left it. Removing it doesn't change anything. – Equalsk May 19 '16 at 14:55
  • 2
    To whomever is downvoting, can you please leave a comment suggesting how this post can be improved. Stealth downvoting on what I believe is a clear question is not helpful. – Equalsk May 19 '16 at 15:04
  • I think it has nothing to do with your code. the menu will show at where the system think it best fit. if you drag your application(window) to the far left of the screen, the menu will be displayed to the right (or left to right). – Bolu May 19 '16 at 15:06
  • Oh, so this is just normal behaviour for WPF that has changed since WinForms. OK, I guess that makes sense then. Thanks. – Equalsk May 19 '16 at 15:11
  • Is your WPF targeting the same .NET version as your `WinFroms`? And no this isn't normal behaviour for WPF if your Window is in center of the screen. – XAMlMAX May 19 '16 at 15:12
  • The target version of .NET is irrelevant... – Equalsk May 19 '16 at 15:13
  • No it's not just WPF, this is true also for WinForm. – Bolu May 19 '16 at 15:19
  • XAMIMAX: It does seem to be the normal behaviour. Now it's been pointed out to me I've noticed that several other apps behave this way including Visual Studio. Bolu: Are you sure? None of my WinForms projects behave this way and never have. I'll have to go and check some more. – Equalsk May 19 '16 at 15:20
  • @Equalsk just a note: this is the kind of property you would globally set for all windows in the app.xaml file. – Dbl May 19 '16 at 15:57
  • Have you got an example of that? The file is pretty empty and I can't find any documentation on this. – Equalsk May 19 '16 at 16:00
  • @Equalsk if you can't find any documentation on it that's because you have not been looking at all. there is tons of it on google :) – Dbl May 19 '16 at 17:06
  • That was really unhelpful. Don't be a jerk. I'm new to WPF and don't know what I'm looking for. If you don't want to help then just go somewhere else, I'm not making you read this thread... – Equalsk May 19 '16 at 17:09
  • @Equalsk ok. fair enough. These are the keywords you are looking for: "app xaml inherit style" – Dbl May 19 '16 at 17:11
  • @Equalsk If you are new to WPF make sure to inform yourself about MVVM, Commands, Triggers and Converters. That will make your life easier most of the time. – Dbl May 19 '16 at 17:13
  • I didn't get notified from your comment, you need to use '@' sign before my username. And when I am creating a new WPF application with en-GB culture as default, my Menu opens to the right every time, so I will disagree with your statement that this is normal behavior. I also used your code and the menu appears on the right. – XAMlMAX May 20 '16 at 08:58
  • @XAMIMAX Could you please check whether changing the setting from [my answer](http://stackoverflow.com/a/37327112/3506292) affects the way the menus are shown on your machine? – filhit May 20 '16 at 10:38

3 Answers3

12

The way menus are opened depends on the SystemParameters.MenuDropAlignment property. This is usually set to align to the right if you have a tablet computer configured for right-handed people.

The setting can be changed for the computer in Control Panel -> Tablet PC Settings -> Specify which hand you write with. If you don't have Tablet PC Settings in your control panel you can try running shell:::{80F3F1D5-FECA-45F3-BC32-752C152E456E}. That should open Tablet PC Settings configuration dialog (source: https://stackoverflow.com/a/25109673/3506292). There is also a registry key you can create to change this setting.

You can use answers from this or that questions to override this behavior if it is absolutely required.

The easiest change (from https://stackoverflow.com/a/22065976/3506292)

private static readonly FieldInfo _menuDropAlignmentField;
static MainWindow()
{
    _menuDropAlignmentField = typeof(SystemParameters).GetField("_menuDropAlignment", BindingFlags.NonPublic | BindingFlags.Static);
    System.Diagnostics.Debug.Assert(_menuDropAlignmentField != null);

    EnsureStandardPopupAlignment();
    SystemParameters.StaticPropertyChanged += SystemParameters_StaticPropertyChanged;
}

private static void SystemParameters_StaticPropertyChanged(object sender, PropertyChangedEventArgs e)
{
    EnsureStandardPopupAlignment();
}

private static void EnsureStandardPopupAlignment()
{
    if (SystemParameters.MenuDropAlignment && _menuDropAlignmentField != null)
    {
        _menuDropAlignmentField.SetValue(null, false);
    }
}
Community
  • 1
  • 1
filhit
  • 2,084
  • 1
  • 21
  • 34
  • 1
    I'm sorry but I don't really understand your answer. I'm not on a tablet, this is a standard desktop PC. On the same PC in a WinForms project the menus open correctly, it's only in WPF they're reversed. I'm sure I'm just missing a property somewhere, having to write a massive override method seems like overkill to me and isn't addressing the actual cause. – Equalsk May 19 '16 at 15:06
  • @Equalsk It's very easy to identify. Just check the value of SystemParameters.MenuDropAlignment. If it is true, the popups are configured to appear right to left. On my machine the popups are opened right to left, and after I apply the solution from [this answer](http://stackoverflow.com/a/22065976/3506292) they are appearing left to right. So it is the actual cause (at least for my machine). – filhit May 19 '16 at 15:21
  • @Equalsk You can also check Control Panel -> Tablet PC Settings -> Specify which hand you write with [(source answer)](http://stackoverflow.com/a/12929571/3506292). There are two options "Right-handed - Menus appear to the left of your hand." and "Left-handed - Menus appear to the right of your hand." Switch this radio button, press apply and see the changes in your app. – filhit May 19 '16 at 15:32
  • 3
    I have the same issue on desktop PC (Windows 10) after connecting a second monitor with built-in touchscreen (Dell P2418HT). And I found a shorter version of your code: https://www.red-gate.com/simple-talk/blogs/wpf-menu-displays-to-the-left-of-the-window/ – SLA80 Sep 21 '20 at 10:33
3

I was able to implement the fix by using the code from @SLA80's link in their comment on the approved answer above.

Inside the App.xaml.cs, I added this code:

private static void SetDropDownMenuToBeRightAligned()
    {
        var menuDropAlignmentField = typeof(SystemParameters).GetField("_menuDropAlignment", BindingFlags.NonPublic | BindingFlags.Static);
        Action setAlignmentValue = () =>
        {
            if (SystemParameters.MenuDropAlignment && menuDropAlignmentField != null) menuDropAlignmentField.SetValue(null, false);
        };

        setAlignmentValue();

        SystemParameters.StaticPropertyChanged += (sender, e) =>
        {
            setAlignmentValue();
        };
    }

I call this function from the App constructor.

Keith Sirmons
  • 8,271
  • 15
  • 52
  • 75
2

Very late to this show, but nonetheless here's my fix. Of course changing the registry entry solves the problem:

HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows

change

REG_SZ: MenuDropAlignment

according to your wishes. Value 0 means right, 1 is left.

But you can't suppose a user would look up and find this issue if your layout looks crappy. The fix is to apply a Datatrigger in the MenuItem Style. Look for the 'PART_Popup' in 'TopLevelHeaderTemplate' e.g.

 <Popup
    x:Name="PART_Popup"
    AllowsTransparency="true"
    Focusable="false"
    IsOpen="{Binding IsSubmenuOpen, RelativeSource={RelativeSource TemplatedParent}}"
    Placement="Bottom"
    PlacementTarget="{Binding ElementName=templateRoot}"
    PopupAnimation="{DynamicResource {x:Static SystemParameters.MenuPopupAnimationKey}}"
    >

And apply a DataTrigger:

 <DataTrigger Binding="{Binding Source={x:Static SystemParameters.MenuDropAlignment}}" Value="True">
     <Setter TargetName="PART_Popup" Property="Placement" Value="Left" />
     <Setter TargetName="PART_Popup" Property="HorizontalOffset" Value="{Binding ElementName=templateRoot, Path=ActualWidth, Converter={StaticResource NegativeConverter}}" />
     <Setter TargetName="PART_Popup" Property="VerticalOffset" Value="{Binding ElementName=templateRoot, Path=ActualHeight}" />
 </DataTrigger>

This worked for me, as changing the registry entry produces same result.

user947737
  • 326
  • 2
  • 11