Metro Theme in Designmode.. HOWTO

WPF Studio, Themes, and Shared Library for WPF Forum

Posted 4 years ago by keepITcool - Amsterdam
Version: 15.1.0623
Avatar

Dear fellow developers:

Metro and Office themes require code to load and initialize the theme resources... and we've gotten used to "blind design" with the base theme and having to run the app to actually see the themed windows and controls.

No Longer!  

VS2015 has a new Xaml designer which (finally) has the ability to run code in designmode. For VS2013 and earlier you'll need a bit of extra code and two nuget packages from Fody to achieve the same...

First prep the code: 

Public Class ThemeHelper
    Shared _IsInitialized As Boolean
    Shared Sub Initialize()
        If Not _IsInitialized Then
            ActiproSoftware.Windows.Themes.ThemeManager.BeginUpdate()
            'Register Metro  (requires reference to ActiproSoftware.Themes.Metro.Wpf)
            ActiproSoftware.Windows.Themes.ThemesMetroThemeCatalogRegistrar.Register()
            'Register Office (requires reference to ActiproSoftware.Themes.Office.Wpf)
            ActiproSoftware.Windows.Themes.ThemesOfficeThemeCatalogRegistrar.Register()
            ActiproSoftware.Windows.Themes.ThemeManager.EndUpdate()
            _IsInitialized = True
        End If
    End Sub
End Class

You can call this code in the constructor of your Application object, or if you're not running a WPF application call it in the constructor of the Control or Window you're designing. Just do it BEFORE InitializeComponents.

Class Application
    Public Sub New()
        ThemeHelper.Initialize()
    End Sub

    ' Application-level events, such as Startup, Exit, and DispatcherUnhandledException
    ' can be handled in this file.
End Class

' OR

Class MainWindow
    Public Sub New()
        ThemeHelper.Initialize()

        ' This call is required by the designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.
    End Sub
End Class

In your window or control's xaml: choose: but if you mix the runtime settings take precedence!

themes:ThemeManager.AreNativeThemesEnabled="True"
themes:ThemeManager.Theme="MetroLight" 

 

themes:ThemeManager.DesignModeAreNativeThemesEnabled="True"
themes:ThemeManager.DesignModeTheme="MetroDark"

Mixing the above DesignMode and Runtime attached properties may not be the best idea.. the designer will show the runtime theme of MetroLight... in my experience it's best the set the DesignTimeTheme only... and leave the runtime theme to the global ThemeManager.

In VS2015:

goto Tools/Options/Xaml Designer/General and check : "Run Project code in XAML designer (if supported)"

Now you will see your control in all it's themed glory right in the designer!

Note: You'll need to rebuild your project if you make changes to the xaml defined theme..

 

 

 

For VS2013:

You'll need the nuget package manager extenstion.

Install Fody ( a package for weaving .Net assemblies)
Install Fody/ModuleInit (https://github.com/Fody/ModuleInit)

My packages.config looks like:

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Fody" version="1.29.3" targetFramework="net4" developmentDependency="true" />
  <package id="ModuleInit.Fody" version="1.5.8.0" targetFramework="net46" developmentDependency="true" />
</packages>

Insert or update a file called FodyWeavers.xml: Mine looks like:

<?xml version="1.0" encoding="utf-8"?>
<Weavers>
  <ModuleInit />
</Weavers>

ModuleInit will add a file called ModuleInitializer.cs to your vb project. Never mind:  easily removed and replaced with the translated vb class.

I've dumped all required class in a single file called DesignTimeStuff.vb...

' This could be moved to AssemblyInfo
<Assembly: DesignTimeCode(GetType(Initializer))>

<HideModuleName> Module DesignModeHelper
    Function IsInDesignMode() As Boolean
        Return System.ComponentModel.DesignerProperties.GetIsInDesignMode(New DependencyObject)
    End Function
End Module

''' <summary>
''' This code is called at designtime builds
''' </summary>
''' <remarks></remarks>
Public Class Initializer
    Inherits DesignTimeInitializerBase

    Protected Overrides Sub Initialize()
        Application.InitializeThemes()
    End Sub
End Class

''' <summary>
''' ModuleInitializer is required by ModuleInit.Fody (via FodyWeavers.xml)
''' </summary>
''' <remarks></remarks>
Public NotInheritable Class ModuleInitializer
    Public Shared Sub Initialize()
        If IsInDesignMode() Then
            For Each assembly In AppDomain.CurrentDomain.GetAssemblies()
                Dim attributes = assembly.GetCustomAttributes(GetType(DesignTimeCodeAttribute), True)
                ' No need to do anything
                For Each attribute In attributes
                Next
            Next
        End If
    End Sub
End Class


''' <summary>
''' Specifies a type(class) to be constructed during DesignTime
''' </summary>
''' <remarks></remarks>
<AttributeUsage(AttributeTargets.Assembly, AllowMultiple:=True)> _
Public Class DesignTimeCodeAttribute
    Inherits Attribute
    Private Shared ReadOnly InitializedTypes As New Dictionary(Of Type, Boolean)()

    Public Sub New(typeToConstruct As Type)
        If InitializedTypes.ContainsKey(typeToConstruct) Then
            Return
        End If

        InitializedTypes(typeToConstruct) = True

        If IsInDesignMode() Then
            Activator.CreateInstance(typeToConstruct)
        End If
    End Sub
End Class

''' <summary>
''' Represents the base class for implementing DesignTime Initializers
''' </summary>
''' <remarks></remarks>
Public MustInherit Class DesignTimeInitializerBase
    Public Sub New()
        If CanInitialize Then
            Initialize()
        End If
    End Sub

    Public ReadOnly Property CanInitialize() As Boolean
        Get
            Return IsInDesignMode()
        End Get
    End Property

    Protected Overridable Sub Initialize()
    End Sub
End Class

 

 HTH..

 questions to keepitcool@outlook.com

 

Jurgen

[Modified 4 years ago]

The latest build of this product (v2019.1 build 0682) was released 30 days ago, which was after this thread was created.

Add Comment

Please log in to a validated account to post comments.