0

I'm creating a WPF application using the ModernUI framework and I'm having trouble nesting a ModernMenu control in my MainWindow class. Here's what I had initially for my MainWindow:

<mui:ModernWindow x:Class="MyApp.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:mui="http://firstfloorsoftware.com/ModernUI"
    xmlns:local="clr-namespace:MyApp"
    mc:Ignorable="d"
    Title="MyApp" IsTitleVisible="True" Height="350" Width="525" WindowState="Maximized" ContentSource="/Views/SourcePage1.xaml">

<mui:ModernWindow.MenuLinkGroups >
    <mui:LinkGroup x:Name="sourceGroup" DisplayName="Source">
        <mui:LinkGroup.Links>
            <mui:Link x:Name="sourceLink1" DisplayName="File" Source="/Views/SourcePage1.xaml"/>
            <mui:Link x:Name="sourceLink2" DisplayName="Instrumentation" />
        </mui:LinkGroup.Links>
    </mui:LinkGroup>
</mui:ModernWindow.MenuLinkGroups>

In "SourcePage1.xaml" I try to add a second sub-menu (an instance of ModernMenu):

<UserControl x:Class="MyApp.Views.SourcePage1"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:mui="http://firstfloorsoftware.com/ModernUI"
         xmlns:local="clr-namespace:MyApp.Views"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">

<Grid x:Name="mainGrid" Margin="0,10,0,0">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="2*"/>
        <ColumnDefinition Width="4"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>

    <Border x:Name="initialSpacer" Grid.Column="0" Background="Transparent" BorderBrush="DimGray" BorderThickness="2">
        <Grid>
            <Label Content="Ready" FontSize="40" Foreground="DimGray" HorizontalAlignment="Center" VerticalAlignment="Center"/>
        </Grid>
    </Border>

    <GridSplitter Grid.Column="1" Width="4" HorizontalAlignment="Center" VerticalAlignment="Stretch"/>

        <mui:ModernMenu Grid.Column="2">
            <mui:ModernMenu.LinkGroups>
                <mui:LinkGroup DisplayName="Catagory1">
                    <mui:LinkGroup.Links>
                        <mui:Link x:Name="catagory1Link" DisplayName="name1" Source="/Views/SettingsPage.xaml"/>
                        <mui:Link DisplayName="insert" />
                    </mui:LinkGroup.Links>
                </mui:LinkGroup>
                <mui:LinkGroup DisplayName="Catagory2">
                    <mui:LinkGroup.Links>
                        <mui:Link DisplayName="name1" />
                        <mui:Link DisplayName="name2" />
                        <mui:Link DisplayName="name3" />
                    </mui:LinkGroup.Links>
                </mui:LinkGroup>
                <mui:LinkGroup DisplayName="Catagory3">
                    <mui:LinkGroup.Links>
                        <mui:Link DisplayName="name1" />
                    </mui:LinkGroup.Links>
                </mui:LinkGroup>
            </mui:ModernMenu.LinkGroups>
        </mui:ModernMenu>

</Grid>

Where "SettingsPage.xaml" is just for testing:

<UserControl x:Class="MyApp.Views.SettingsPage"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:mui="http://firstfloorsoftware.com/ModernUI"
         xmlns:local="clr-namespace:MyApp.Views"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">

<Grid x:Name="mainGrid" Margin="0,10,0,0">
      <Label Content = "Hi there!"/>     
</Grid>

The MainWindows' ModernMenu shows up and works well. Likewise, the ModernMenu on "SourcePage1.xaml" also shows up just fine, but I cannot seem to be able to assign it any source content. When I click on any of the links that have been assigned content (like "catagory1Link") nothing appears. What could be the problem here? Am I not allowed to nest menus like this?

LKeene
  • 627
  • 1
  • 8
  • 22

2 Answers2

2

The ModernMenu doesn't auto navigate the frame, as you stated. You could use a ModernTab instead but it will setup another ModernFrame and that frame is the one the links set the source on.

ModernMenu does have a SelectedLink DependencyProperty though. If you bind it to a property on your usercontrol, you can detect the link click and navigate the frame yourself.

SourcePage1.xaml

<mui:ModernMenu Grid.Column="1" SelectedLink="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}, Path=MenuSelectedLink, Mode=OneWayToSource}">

SourcePage1.xaml.cs

using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Controls;
using FirstFloor.ModernUI.Presentation;

namespace WpfApp17
{
    public partial class SourcePage1 : UserControl, INotifyPropertyChanged
    {
        public SourcePage1()
        {
            InitializeComponent();
        }

        #region Property Link MenuSelectedLink
        private Link _MenuSelectedLink;
        public Link MenuSelectedLink { get { return _MenuSelectedLink; } set { SetProperty(ref _MenuSelectedLink, value); OnMenuSelectedLinkChanged(); } }
        #endregion

        private void OnMenuSelectedLinkChanged()
        {
            if (MenuSelectedLink == null || MenuSelectedLink.Source == null)
                return;

            // Navigate the frame to the source. 
            var frame = FirstFloor.ModernUI.Windows.Navigation.NavigationHelper.FindFrame(null, this);
            if (frame != null)
            {
                if (frame.Source != MenuSelectedLink.Source)
                    frame.Source = MenuSelectedLink.Source;
            }
        }

        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        protected bool SetProperty<T>(ref T field, T value, [CallerMemberName]string name = null)
        {
            if (Equals(field, value))
            {
                return false;
            }
            field = value;
            this.OnPropertyChanged(name);
            return true;
        }
        protected void OnPropertyChanged([CallerMemberName]string name = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
        #endregion
    }
}
J.H.
  • 4,232
  • 1
  • 18
  • 16
  • Thank you very much for that suggestion. The code is complex and I don't really understand your solution (I'll read up on INotifyPropertyChanged) but I quickly tried it nonetheless. It almost works! When I select the link it does now display the test page ("SettingsPage") but it replaces the entire content of SourcePage1 with SettingsPage content, rather than displaying SettingsPage in the 3rd grid column (and underneath the modern menu) of SourcePage1. Is there a workaround to this? – LKeene Feb 08 '18 at 23:28
0

J.H.'s solution is correct and I've marked it as such. I only changed things a little to get the behavior I was looking for: I created a new UserControl consisting simply of a "ModernMenu" object in the first row of the grid and a "ModernFrame" in the second row. The frame is named "pageFrame". Then, I just add the content directly to pageFrame when the menu link changes in this new UserControls' code-behind file:

        private void OnMenuSelectedLinkChanged()
    {
        if (MenuSelectedLink == null || MenuSelectedLink.Source == null)
            return;

        // Navigate the frame to the source. 
        pageFrame.Source = MenuSelectedLink.Source;
    }
LKeene
  • 627
  • 1
  • 8
  • 22