9

I have a main menu mnuMainMenu consisting of several sub-menus. One of the sub-menus mnuMostRecentDirs is itself another menu that has it's items generated at run time, using the ItemSource property bound to an ObservableCollection. Basically it's displaying a list of the most recently used folders.

The issue is that the MenuItems added dynamically generate the following data binding error:

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.ItemsControl', AncestorLevel='1''. BindingExpression:Path=HorizontalContentAlignment; DataItem=null; target element is 'MenuItem' (Name=''); target property is 'HorizontalContentAlignment' (type 'HorizontalAlignment')

The XAML declaration of the main menu goes something like this:

 <!-- Main Menu -->
 <Menu x:Name="mnuMainMenu" Height="Auto" IsMainMenu="True">

    <!--- ... more menu declarations before ... -->

    <MenuItem x:Name="mnuitemWorkDirs" Header="Directories">
       <MenuItem x:Name="mnuNewDir"
                 Header="New" 
                 Style="{StaticResource MenuItem}" 
                 Command="{x:Static cmds:Commands.NewDirectory}" />
       <MenuItem x:Name="mnuCurrentDir"
                 Header="Current" 
                 Style="{StaticResource MenuItem}"
                 Command="{x:Static cmds:Commands.CurrentDirectory}" />
       <MenuItem x:Name="mnuMostRecentDirs" 
                 Header="Recent Directories.."
                 Style="{StaticResource MenuItem}"
                 ItemsSource="{Binding ElementName=theMain, Path=MostRecentFoldersList}" />
    </MenuItem>

    <!--- ... more menu declarations after ... -->
 </Menu>

And the following code adds folders to the observable collection at run time:

    private void PopulateMostRecentFoldersList(string[] paths) 
    {
        MostRecentFoldersList.Clear();

        if (paths == null)
           return;

        foreach (var fullPath in paths)
        {                                        
            var mi = new MenuItem();
            mi.Command = Commands.ChooseWorkingDirectory;
            mi.CommandParameter = fullPath;

            string name = System.IO.Path.GetFileName(fullPath);

            mi.Header = name.ToUpper();                

            // removing this style completely
            //     or manually setting the HorizontalContentAlignment property here 
            //     prevents the binding error from happening
            mi.Style = (Style)FindResource("MenuItem");                    

            MostRecentFoldersList.Add(mi);
        }
    }

I was able to trace the problem to a binding declared in the style for MenuItem which is not declared in my application. I assume it's the default style for menu items..

None of the other menu items appear to be having any binding problems with the same style being applied to all.

So I'm thinking that the problem must be my approach to adding the MenuItems dynamically. More specifically it seems that the style is being applied to the MenuItem before the item is added to the ItemsControl.

So far I could only come up with setting the HorizontalContentAlignment property in code, on the MenuItem before adding it to the observable collection, but that is just a band-aid and it's only really masking the real problem.

Community
  • 1
  • 1
Mike Dinescu
  • 54,171
  • 16
  • 118
  • 151
  • 1
    Please see the [answer here](http://social.msdn.microsoft.com/Forums/en/wpf/thread/f3549b2b-5342-41a1-af04-d55e43c48768) – LPL Jan 25 '13 at 17:24
  • @LPL - thanks for posting that link. You should have made it an answer though.. – Mike Dinescu Jan 25 '13 at 19:10

2 Answers2

12

As pointed out by @LPL - it turns out this is a known (acknowledged) problem in the WPF framework. Based on information found on MSDN support forums here and here, it appears that when setting the ItemsSource of a MenuItem to a collection of MenuItems it doesn't handle things in the correct order

Per MSDN Support staff:

This happens when you set MenuItem.ItemsSource to a Collection that contains MenuItems. This error has already been handled internally, so you can just leave it alone.

Or you can explicit set MenuItem.HorizontalContentAlignment property and VerticalContentAlignment property to avoid this error. You can simply put the following code in application.Resource to achieve this.

  <Style TargetType="MenuItem">
   <Setter Property="HorizontalContentAlignment" Value="Left"/>
   <Setter Property="VerticalContentAlignment" Value="Center"/>
  </Style>

I hope this helps others having the same issue.

Mike Dinescu
  • 54,171
  • 16
  • 118
  • 151
  • 1
    Exact same issue as you, very annoying binding error, but this solves it for now. Anyone know if it's been 'fixed' since 2013?! – Grim Aug 03 '16 at 12:41
1

I really think it's not a good idea or ""WPF compatible"" to add UIelemnts from code.

I would suggest something like this:

    <Menu>
        <MenuItem Header="MainMenu" Name="sampleMenu">
            <MenuItem.ItemTemplate>
                <DataTemplate>
                    <MenuItem Header="{Binding Path=PathtoNameOfRecentDocObject}"/>
                </DataTemplate>
            </MenuItem.ItemTemplate>
        </MenuItem>
    </Menu>

and set MainMenu's ItemsSource to MostRecentFoldersList

iltzortz
  • 2,342
  • 2
  • 19
  • 35
  • 1
    I agree with you, it's not 100% WPF from a philosophical stand point. That said, the behaviour is strange nonetheless and I was trying to understand what is causing it and how to be able to more easily debug problems like this in the future. – Mike Dinescu Jan 25 '13 at 19:09
  • The same error appears when creating the menu hierarchy from a hierarchical model and modify the menus via binding. The problem is not fixed since... Its only annoying because I have a binding error handler in debug mode in order to investigate binding errors and it stops every time I log in with a different user... – Daniel Leiszen Oct 24 '18 at 11:46