A: 

Try using a HierarchicalDataTemplate with an internal ContentPresenter instead. Take a look at this SO answer for more details.

Mark Seemann
The SO answer you linked is really for a sub menu. What I'd like is the dynamic list to be a part of a non dynamic menu... Do you have any other idea?
Julien Poulin
So basically you want to merge some dynamic MenuItems into a statically defined Menu? AFAIK, when you do databinding, either you bind a complete ItemsSource, or you build the contents manually (either in XAML or from code). What I would do would be to make the entire menu databound to a MenuItemViewModel, but then make sure via the API that only the dynamic list was editable.
Mark Seemann
+3  A: 

The "weird offset" is a MenuItem. The parent MenuItem is already generating a child MenuItem for you, but your DataTemplate adds a second one. Try this:

<MenuItem Header="File}">
  <MenuItem Header="Preferences..." Command="{Binding ShowOptionsViewCommand}" />
  <Separator />
  <ItemsControl ItemsSource="{Binding RecentFiles}">
    <ItemsControl.ItemTemplate>
      <DataTemplate>
        <TextBlock Text="{Binding DisplayPath}"/>
      </DataTemplate>
    </ItemsControl.ItemTemplate>
    <ItemsControl.ItemContainerStyle>
      <Style TargetType="MenuItem">
        <Setter Property="Command" Value="{Binding DataContext.OpenRecentFileCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"/>
        <Setter Property="CommandParameter" Value="{Binding}"/>
      </Style>
    </ItemsControl.ItemContainerStyle>
  </ItemsControl>
  <Separator />
  <MenuItem Header="Exit" Command="{Binding CloseCommand}" />
</MenuItem>

Note the simplified DataTemplate that just contains a TextBlock, and the ItemContainerStyle to set properties on the generated MenuItem.

HTH, Kent

Kent Boogaart
This looks promising but I get an exception stating that *A style intended for type 'MenuItem' cannot be applied to type 'ContentPresenter'*. Do you have an idea how to fix that?
Julien Poulin
Didn't read your code properly. You can't really mix generated items with non-generated. Get rid of the ItemsControl and bind the top-level MenuItem instead. Just stick the non-generated items like Preferences in the collection of menu items, or use a CompositeCollection to keep them separate.
Kent Boogaart
I tried using a CompositeCollection but I cannot bind a CollectionContainer to my VM because of a bug in wpf. I don't want to put the other MenuItem in the list because they don't belong there. So in the end, I just created a 'Recent Files' sub menu (I already had it worked out but I really wanted to have the list in the 'File' menu).
Julien Poulin
+1  A: 

I tried using a CompositeCollection as suggested by Kent Boogaart, but I could make it work because of a bug in wpf not allowing to use a RelativeSource binding in a CollectionContainer.

The solution I used is to have the RecentFiles in its own sub menu bound to the Collection via the ItemsSource property.

I really wanted to have the list in the 'File' menu but I guess this is the next best thing...

Edit

Inspired by this article I built a custom and more general MenuItemList:

public class MenuItemList : Separator {

  #region Private Members

  private MenuItem m_Parent;
  private List<MenuItem> m_InsertedMenuItems;

  #endregion

  public MenuItemList() {
    Loaded += (s, e) => HookFileMenu();
  }

  private void HookFileMenu() {
    m_Parent = Parent as MenuItem;
    if (m_Parent == null) {
      throw new InvalidOperationException("Parent must be a MenuItem");
    }
    if (ParentMenuItem == m_Parent) {
      return;
    }
    if (ParentMenuItem != null) {
      ParentMenuItem.SubmenuOpened -= _FileMenu_SubmenuOpened;
    }
    ParentMenuItem = m_Parent;
    ParentMenuItem.SubmenuOpened += _FileMenu_SubmenuOpened;
  }

  private void _FileMenu_SubmenuOpened(object sender, RoutedEventArgs e) {
    DataBind();
  }

  #region Properties

  public MenuItem ParentMenuItem { get; private set; }

  #region ItemsSource

  /// <summary>
  /// ItemsSource Dependency Property
  /// </summary>
  public static readonly DependencyProperty ItemsSourceProperty =
      DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(MenuItemList),
          new FrameworkPropertyMetadata(null,
              new PropertyChangedCallback(OnItemsSourceChanged)));

  /// <summary>
  /// Gets or sets a collection used to generate the content of the <see cref="MenuItemList"/>. This is a dependency property.
  /// </summary>
  public IEnumerable ItemsSource {
    get { return (IEnumerable) GetValue(ItemsSourceProperty); }
    set { SetValue(ItemsSourceProperty, value); }
  }

  /// <summary>
  /// Handles changes to the ItemsSource property.
  /// </summary>
  private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
    ((MenuItemList) d).OnItemsSourceChanged(e);
  }

  /// <summary>
  /// Provides derived classes an opportunity to handle changes to the ItemsSource property.
  /// </summary>
  protected virtual void OnItemsSourceChanged(DependencyPropertyChangedEventArgs e) {
    DataBind();
  }

  #endregion

  #region ItemContainerStyle

  /// <summary>
  /// ItemsContainerStyle Dependency Property
  /// </summary>
  public static readonly DependencyProperty ItemContainerStyleProperty =
      DependencyProperty.Register("ItemContainerStyle", typeof(Style), typeof(MenuItemList),
          new FrameworkPropertyMetadata((Style) null));

  /// <summary>
  /// Gets or sets the <see cref="System.Windows.Style"/> that is applied to the container element generated for each item. This is a dependency property.
  /// </summary>
  public Style ItemContainerStyle {
    get { return (Style) GetValue(ItemContainerStyleProperty); }
    set { SetValue(ItemContainerStyleProperty, value); }
  }

  #endregion

  #endregion

  private void DataBind() {
    RemoveMenuItems();
    InsertMenuItems();
  }

  private void RemoveMenuItems() {
    if (m_InsertedMenuItems != null) {
      foreach (var menuItem in m_InsertedMenuItems) {
        ParentMenuItem.Items.Remove(menuItem);
      }
    }
  }

  private void InsertMenuItems() {
    if (ItemsSource == null) {
      return;
    }
    if (ParentMenuItem != null) {
      m_InsertedMenuItems = new List<MenuItem>();
      int iMenuItem = ParentMenuItem.Items.IndexOf(this);
      foreach (var item in ItemsSource) {
        var menuItem = new MenuItem();
        menuItem.DataContext = item;
        menuItem.Style = ItemContainerStyle;
        ParentMenuItem.Items.Insert(++iMenuItem, menuItem);
        m_InsertedMenuItems.Add(menuItem);
      }
    }
  }

}

It's far from perfect but it works for me. Feel free to comment on it...

Julien Poulin
A: 

This blog article shows how to make data-driven menus:

http://weblogs.asp.net/okloeten/archive/2007/11/14/5149692.aspx

Ashley Davis