17

does anyone have an example or tutorial on how to use Caliburn Micro together with ModernUi (https://mui.codeplex.com)?

Athari
  • 33,702
  • 16
  • 105
  • 146
Matthias
  • 340
  • 1
  • 2
  • 8
  • 1
    I'd imagine since ModernUI looks like a collection of controls that you would just need to add the conventions for each control in the toolkit. The only difference would be that CM uses ChildWindow for most of it's window management, and you'd probably want to replace this with ModernWindow in your implementation. I think you would probably only need to provide your own implementation for WindowManager (and specifically `EnsureWindow` method) http://caliburnmicro.codeplex.com/SourceControl/changeset/view/35582bb2a8dfdd3fcd71a07fa82581ddb93a786f#src/Caliburn.Micro.Silverlight/WindowManager.cs – Charleh May 07 '13 at 14:35
  • 1
    Well, after having a look, it looks to be more complex than that. I think that providing your own WindowManager implementation might not be the best idea since all popups would also implement the `ModernWindow` class. Also it looks like it loads content dynamically based on resource URLs and therefore a viewmodel-first approach would probably not work. – Charleh May 08 '13 at 08:20

2 Answers2

21

Ok so I had a quick mess about with it and a look on the Mui forums and this seems to be the best approach:

Since the window loads content from URLs you need to take a view-first approach, and then locate the appropriate VM and bind the two.

The best way to do this appears to be via the ContentLoader class which is used to load the content into the ModernWindow when it is requested. You can just subclass DefaultContentLoader and provide the necessary CM magic to bind up loaded items:

public class ModernContentLoader : DefaultContentLoader
{
    protected override object LoadContent(Uri uri)
    {
        var content = base.LoadContent(uri);

        if (content == null)
            return null;

        // Locate the right viewmodel for this view
        var vm = Caliburn.Micro.ViewModelLocator.LocateForView(content);

        if (vm == null)
            return content;

        // Bind it up with CM magic
        if (content is DependencyObject)
        {
            Caliburn.Micro.ViewModelBinder.Bind(vm, content as DependencyObject, null);
        }

        return content;
    }
}

Your CM bootstrapper should just bootstrap a ModernWindow viewmodel which is backed by a ModernWindow based view (CM tries to use EnsureWindow which creates a new basic WPF Window class, unless of course your control already inherits from Window which ModernWindow does. If you need all dialogs and popups to be MUI you might need to reimplement WindowManager):

public class Bootstrapper : Bootstrapper<ModernWindowViewModel>
{
}

Which can be a conductor (OneActive) and looks like this:

public class ModernWindowViewModel : Conductor<IScreen>.Collection.OneActive
{
}

And XAML for the view is

ModernWindowView.xaml

<mui:ModernWindow x:Class="WpfApplication4.ViewModels.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"
                                     Title="ModernWindowView" Height="300" Width="300" ContentLoader="{StaticResource ModernContentLoader}">   
    <mui:ModernWindow.MenuLinkGroups>
        <mui:LinkGroupCollection>
            <mui:LinkGroup GroupName="Hello" DisplayName="Hello">
                <mui:LinkGroup.Links>
                    <mui:Link Source="/ViewModels/ChildView.xaml" DisplayName="Click me"></mui:Link>
                </mui:LinkGroup.Links>
            </mui:LinkGroup>
        </mui:LinkGroupCollection>
    </mui:ModernWindow.MenuLinkGroups>
</mui:ModernWindow>

Obviously you need to make the loader a resource too:

<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="/FirstFloor.ModernUI;component/Assets/ModernUI.xaml" />
            <ResourceDictionary Source="/FirstFloor.ModernUI;component/Assets/ModernUI.Dark.xaml"/>
            <ResourceDictionary>
                <framework:ModernContentLoader x:Key="ModernContentLoader"></framework:ModernContentLoader>
                <wpfApplication4:Bootstrapper x:Key="Bootstrapper"></wpfApplication4:Bootstrapper>
            </ResourceDictionary>
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

Here's the ChildViewModel I'm using as a test:

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

And the XAML for that (just a button)

<UserControl x:Class="WpfApplication4.ViewModels.ChildView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                                     Height="350" Width="525">
    <Grid>
        <StackPanel>
        <TextBlock >Hello World</TextBlock>
        <Button x:Name="ClickMe" Width="140" Height="50">Hello World</Button>
        </StackPanel>
    </Grid>
</UserControl>

And the proof of concept:

MUI Example

Charleh
  • 13,749
  • 3
  • 37
  • 57
  • Hey Charleh, thanks again for your answer. There is one problem left: In the ContentLoader, when the ViewLocator looks for the matching viewmodel, it always returns null and no Binding ist done. Any Idea? – Matthias May 08 '13 at 22:01
  • Charleh, could you upload your working sample source somewhere? – Matthias May 08 '13 at 22:13
  • Yeah I'll do it tomorrow it's sleep time now! Mine resolves the vm correctly, might be something to do with your namespaces, what namespace did you put your view/vm in and what did you call them both? – Charleh May 08 '13 at 23:13
  • I've uploaded it to http://www.filedropper.com/wpfapplication4 - you will probably need to NuGet the packages as I've removed them and I'm not sure if NuGet will get them automatically based on packages.config in the solution dir...I used Castle.Windsor for IoC – Charleh May 09 '13 at 09:11
  • Ah apparently you can use `nuget install packages.config` – Charleh May 09 '13 at 09:12
  • Argh - but create a packages directory in the solution dir first and copy packages.config from the project directory into that, and run it from there, otherwise it dumps them all in your project dir! – Charleh May 09 '13 at 09:14
  • Charleh, thank you very much. Must have been some issues with Castle. Now it just works. – Matthias May 09 '13 at 09:32
  • More info about NuGet here that I didn't know (if it helps) http://stackoverflow.com/questions/6876732/how-do-i-get-nuget-to-install-update-all-the-packages-in-the-packages-config - didn't know you could just do package restore in VS – Charleh May 09 '13 at 09:55
  • According to @AlexJustin, the link with the uploaded application is dead. He has requested that you reupload it if you can to a new host? – Ren May 14 '13 at 08:01
  • 1
    Try it again, I've just reuploaded it to the same place – Charleh May 14 '13 at 08:42
  • 1
    @Charleh, great instruction, thanks! But I can't figure out how to open new popup windows using this combination. I tried to modify WindowManager as shown [here](http://www.mindscapehq.com/blog/index.php/2012/03/13/caliburn-micro-part-5-the-window-manager/) but had no success. Can you help maybe? – AsValeO Mar 15 '15 at 20:28
  • As I get it to achieve the goal I need to import existing WindowManager to ChildViewModel somehow, and then use it to open new window. – AsValeO Mar 15 '15 at 20:46
  • Hi ValeO, do you mind asking this as a new question on SO? That way I can help out without polluting this existing question. Bottom line is, you will probably need to re-implement `WindowManager` and register your own window manager as the implementation for the `IWindowManager` service. This `WindowManager` will use `MordernWindow` instead of the default windows. – Charleh Mar 16 '15 at 13:03
  • Charleh, take a look [here](http://stackoverflow.com/questions/29079328/re-implementing-windowmanager-using-modernui-caliburn-micro-combination) please. Definitely need your help. – AsValeO Mar 16 '15 at 14:30
  • Hi Charleh, can you upload your application once more time. I have the same problem with null reference in ContentLoader. Thanks in advice. – PaulWebbster Apr 28 '15 at 12:30
10

I create a very, very simple sample of chat app using Modern UI for WPF, Caliburn Micro and MEF.

https://github.com/gblmarquez/mui-sample-chat

I hope it helps

gblmarquez
  • 527
  • 3
  • 11
  • How do i navigate using commands? i am getting an error: when i use Command="mui:LinkCommands.NavigateLink". The error is "LinkCommands is not supported in a Windows Presentation Foundation (WPF) project." – Ali123 Aug 11 '21 at 07:20
  • Even BBCodeBlock URL is not showing the URL – Ali123 Aug 11 '21 at 07:27