Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to load content properly inside a ModernWindow using mvvm

At our company, we're used to develop our applications using WinForms, Now we decided to switch to WPF-MVVM with Caliburn.Micro and Modern UI. The thing we're trying to reach is to have a small application that has: - 1 Modern Window - 2 Pages inside that Modern window the goal is to have a button inside that page that navigates the Modern Window to the second page with parameters.

I've been working trying to understand how to work this out, I succeeded with the Window (without the MUI), but when it comes to MUI, it's not really giving me the result we want.

So far, All I did, is

  1. Create a new MUI Project
  2. Add the Caliburn.Micro to the project
  3. Change the App.xaml to

    <Application x:Class="MuiWithCaliburn01.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:MuiWithCaliburn01">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary>
                    <local:AppBootstrapper x:Key="bootstrapper" />
                    <local:ModernContentLoader x:Key="ModernContentLoader" />
                </ResourceDictionary>
                <ResourceDictionary Source="/FirstFloor.ModernUI;component/Assets/ModernUI.xaml" />
                <ResourceDictionary Source="/FirstFloor.ModernUI;component/Assets/ModernUI.Light.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
    

  4. Create the Bootstrapper Class

    
    public class AppBootstrapper : BootstrapperBase
    {
        static AppBootstrapper()
        {
        }
        public AppBootstrapper()
        {
            Initialize();
        }
        protected override void OnStartup(object sender, StartupEventArgs e)
        {
            DisplayRootViewFor();
        }
    }
    
  5. Create the ModernContentLoader Class

    
    public class ModernContentLoader : DefaultContentLoader
    {
        protected override object LoadContent(Uri uri)
        {
            var content = base.LoadContent(uri);
            if (content == null)
                return null;
            var vm = Caliburn.Micro.ViewModelLocator.LocateForView(content);
            if (vm == null)
                return content;
            if (content is DependencyObject)
            {
                Caliburn.Micro.ViewModelBinder.Bind(vm, content as DependencyObject, null);
            }
            return content;
        }
    }
    
  6. ModernWindowView.xaml & ModernWindowViewModel.cs

    
    < mui:ModernWindow x:Class="MuiWithCaliburn01.ModernWindowView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:mui="http://firstfloorsoftware.com/ModernUI"
        ContentLoader="{StaticResource ModernContentLoader}">
    < mui:ModernWindow.MenuLinkGroups>
        < mui:LinkGroupCollection>
            < mui:LinkGroup DisplayName="Hello">
                < mui:LinkGroup.Links>
                    < mui:Link Source="Child1View.xaml" DisplayName="Click me">< /mui:Link>
                < /mui:LinkGroup.Links>
            < /mui:LinkGroup>
        < /mui:LinkGroupCollection>
    < /mui:ModernWindow.MenuLinkGroups>
    < /mui:ModernWindow>
    

    class ModernWindowViewModel : Conductor.Collection.OneActive
    {
        public ModernWindowViewModel()
        {
            //this function is doing nothing in the ModernWindow, but it works great in the Window.
            ActivateItem(new Child1ViewModel());
        }
    }
    

  7. And finally, the Child1View.xaml

    <UserControl x:Class="MuiWithCaliburn01.Child1View"
        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"
        mc:Ignorable="d" 
        xmlns:cal="http://www.caliburnproject.org"
        xmlns:model="clr-namespace:MuiWithCaliburn01"
        d:DataContext="{x:Type model:Child1ViewModel}"
        d:DesignHeight="300" d:DesignWidth="300">
        <Grid>
            <Button cal:Message.Attach="ClickMe" Width="140" Height="50">Hello World</Button>
        </Grid>
    </UserControl>
    

    and Child1ViewModel.cs

    public class Child1ViewModel : Conductor<IScreen>
    {
        public void ClickMe()
        {
            MessageBox.Show("Hello");
        }
    }
    

My question is, step 6, why does the function do nothing? and if my way is wrong can anybody direct me to a better way?

And if it's the best approach, how can I navigate from the function ClickMe to another View.

like image 505
Ahmad Hammoud Avatar asked Apr 04 '16 21:04

Ahmad Hammoud


1 Answers

As for your first question about why does the function do nothing, I think it may have to do with the hierarchy of your project. Using MUI this is the main (and only) window for one of my applications

<mui:ModernWindow x:Class="namespace.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mui="http://firstfloorsoftware.com/ModernUI"
    Title="Window Title" IsTitleVisible="True"
    ContentSource="/Pages/Home.xaml"
    Style="{StaticResource MyModernWindow}">

<mui:ModernWindow.TitleLinks>
    <mui:Link DisplayName="settings" Source="/Pages/SettingsPage.xaml" />
</mui:ModernWindow.TitleLinks>

in my project hierarchy, i have my project root (CSPROJ file), MainWindow.xaml then a Pages folder. Inside my pages folder i have my SettingsPage.xaml. The source attribute in my mui:Link tag points to the realitive path of my main window to my settingsPage.xaml file. MUI will then load and display that path in the content provider that is put in your main window for you by the MUI ModernWindow class default style template. No additional code is needed on your part to navigate (until you want complex sub view navigation).

my settingsPage.xaml file is a normal user control with the grid having a style assigned to the ContentRoot static resource style as it also will contain additional views/pages.

Mui source can be found on GitHub at Mui GithubLink. Here you can download the sample program, who's code is found in the same repository under app Link here for covience.

I am not familiar with Caliburn.Micro so i'm not sure how the two integrate together, such as requirements of Caliburn.Micro to function. I do know how MUI integrates with MVVM light and there are many examples of this found on the internet in my research before hand.

like image 147
xtreampb Avatar answered Sep 23 '22 21:09

xtreampb