Combining MahApps.Metro and Caliburn.Micro
Asked Answered
S

3

14

Well im trying to use MahApps.Metro and Caliburn.Micro together but im getting some problems

Here is my bootstrapper

public sealed class TestBootstrapper : Bootstrapper<ShellViewModel> 
{
    private CompositionContainer container;

    protected override void Configure()
    {
        container = new CompositionContainer(new AggregateCatalog(AssemblySource.Instance.Select(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>()));

        CompositionBatch batch = new CompositionBatch();

        batch.AddExportedValue<IWindowManager>(new AppWindowManager());
        batch.AddExportedValue<IEventAggregator>(new EventAggregator());
        batch.AddExportedValue(container);

        container.Compose(batch);
    }

    protected override object GetInstance(Type serviceType, string key)
    {
        string contract = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(serviceType) : key;
        var exports = container.GetExportedValues<object>(contract);

        if (exports.Count() > 0)
        {
            return exports.First();
        }

        return base.GetInstance(serviceType, key);
    }
}

And here is my AppWindowManager

public sealed class AppWindowManager : WindowManager
{
    static readonly ResourceDictionary[] resources;
    static AppWindowManager()
    {
        resources = new ResourceDictionary[] 
        {
            new ResourceDictionary
            { Source = new Uri("pack://application:,,,/MahApps.Metro;component/Styles/Colours.xaml", UriKind.RelativeOrAbsolute) },
            new ResourceDictionary
            { Source = new Uri("pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml", UriKind.RelativeOrAbsolute) },
            new ResourceDictionary
            { Source = new Uri("pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml", UriKind.RelativeOrAbsolute) },
            new ResourceDictionary
            { Source = new Uri("pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml", UriKind.RelativeOrAbsolute) },
            new ResourceDictionary
            { Source = new Uri("pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml", UriKind.RelativeOrAbsolute) },
            new ResourceDictionary
            { Source = new Uri("pack://application:,,,/MahApps.Metro;component/Styles/Controls.AnimatedTabControl.xaml", UriKind.RelativeOrAbsolute) }
        };
    }

    protected override Window EnsureWindow(object model, object view, bool isDialog)
    {
        MetroWindow window = view as MetroWindow;
        if (window == null)
        {
            window = new MetroWindow()
            {
                Content = view,
                SizeToContent = SizeToContent.WidthAndHeight
            };
            window.MinHeight = 150;
            window.MinWidth = 500;
            foreach (ResourceDictionary resourceDictionary in resources)
            {
                window.Resources.MergedDictionaries.Add(resourceDictionary);
            }
            window.SetValue(View.IsGeneratedProperty, true);
            Window owner = this.InferOwnerOf(window);
            if (owner != null)
            {
                window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
                window.Owner = owner;
            }
            else
            {
                window.WindowStartupLocation = WindowStartupLocation.CenterScreen;
            }
        }
        else
        {
            Window owner2 = this.InferOwnerOf(window);
            if (owner2 != null && isDialog)
            {
                window.Owner = owner2;
            }
        }
        return window;
    }
}

This works somewhat but i get a black border around my window until i resize see image below enter image description here

Why is there a black border and how can i get rid of it (If i manually resize the window the border goes away.)?

Syracuse answered 20/8, 2012 at 21:19 Comment(2)
Thanks for posting this, your code above saved me quite a bit of time!Shaner
github.com/ziyasal/Caliburn.MetroJeans
I
10

With Caliburn.Micro 2 and Mahapps.Metro 1 the above is no longer a valid combination of the two frameworks.

After some digging through Caliburn.Micro documentations and following out dated guides I came up with the following.

First create the bootstrapper like so:

public class AppBootstrapper : BootstrapperBase
{
    private CompositionContainer container;

    public AppBootstrapper()
    {
        Initialize();
    }

    protected override void Configure() 
    {
        container = new CompositionContainer(
            new AggregateCatalog(
                AssemblySource.Instance.Select(
                x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>()
                )
            );

        CompositionBatch batch = new CompositionBatch();

        batch.AddExportedValue<IWindowManager>(new WindowManager());
        batch.AddExportedValue<IEventAggregator>(new EventAggregator());
        batch.AddExportedValue(container);

        container.Compose(batch);

    }

    protected override object GetInstance(Type service, string key) 
    {
        string contract = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(service) : key;
        var exports = container.GetExportedValues<object>(contract);

        if(exports.Any())
        {
            return exports.First();
        }

        throw new Exception(string.Format("Could not locate any instances of contract {0}.", contract));
    }

    protected override IEnumerable<object> GetAllInstances(Type service)
    {
        return container.GetExportedValues<object>(AttributedModelServices.GetContractName(service));
    }

    protected override void BuildUp(object instance) 
    {
        container.SatisfyImportsOnce(instance);
    }

    protected override void OnStartup(object sender, StartupEventArgs e) 
    {
        DisplayRootViewFor<IShell>();
    }
}

Next add the bootstrapper to the App.xaml file along with the MahApps.Metro resources like so:

<Application x:Class="your-namespace.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:your-namespace">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary>
                    <local:AppBootstrapper x:Key="bootstrapper" />
                </ResourceDictionary>
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

The next step is to ensure your ShellViewModel has the proper exports (this is simple requirements for setting up mef bootstrapper, and don't forget to create the IShell class (not going to show that here as it is standard)) like so:

[Export(typeof(IShell))]
public class ShellViewModel : PropertyChangedBase, IShell 
{

}

Last but not least we need to setup the ShellView to use the MahApps.Metro Window:

<Controls:MetroWindow x:Class="your-namespace.ShellView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro">

    <Grid Background="White">
        <TextBlock Text="Hello Caliburn Micro!"
                   VerticalAlignment="Center"
                   HorizontalAlignment="Center"
                   FontSize="20" />
    </Grid>

</Controls:MetroWindow>

Hope this helps anyone else looking to combine Caliburn.Micro and MahApps.Metro in their latest iterations.

Ipa answered 3/2, 2015 at 18:43 Comment(3)
If some one could verify that this is the correct solution then i will mark it as answer!Syracuse
Phil, thankyou for posting this, this worked for me using the latest versions of Caliburn and Mahapps Metro.Ofris
Your post doesn't seem to give any indication as to how new windows are created as MetroWindow's. Caliburn's default WindowManager always creates Windows, not MetroWindows. Do you have a solution for this?Kleper
S
6

It seems that the SizeToContent was the problem!

Syracuse answered 21/8, 2012 at 17:29 Comment(2)
Perhaps you should mark it as the answer then, maybe add some more info if relevant?Hockett
For those interested, it seems that just removing the "SizeToContent = SizeToContent.WidthAndHeight" fixes the problemIdol
O
3

Solution for that problem is setting ResizeMode property to "NoResize" then border is rendered properly.

window = new MetroWindow()
{
    Content = view,
    SizeToContent = SizeToContent.WidthAndHeight,
    ResizeMode = ResizeMode.NoResize
};
Overmatch answered 24/10, 2012 at 13:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.