Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
239 views
in Technique[技术] by (71.8m points)

c# - Is it possible to have skins in xaml outside the sourcecode? (change xaml without recompile)

I have a wpf application with different skins in xaml like this:

    <Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <skins:SkinResourceDictionary ExpressRetailSource="Skins/ExpressRetailColors.xaml"
                                          Lager157Source="Skins/Lager157Colors.xaml" />
            <skins:SkinResourceDictionary ExpressRetailSource="Skins/ExpressRetailImages.xaml"
                                          Lager157Source="Skins/Lager157Images.xaml" />
            <skins:SkinResourceDictionary ExpressRetailSource="Skins/ExpressRetailStyles.xaml"
                                          Lager157Source="Skins/Lager157Styles.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

This is in the app.xml file - and in my config file i pick a skin like this,

        public App()
    {
        ExpressConfiguration.CopyConfigToProgramData();
        var skinConfig = ExpressConfiguration.GetParamValue("Skin", "ExpressRetail");
        switch (skinConfig.ToLower())
        {
            case "expressretail":
            {
                Skin = Skin.ExpressRetail;
                break;
            }
            case "lager157":
            {
                Skin = Skin.Lager157;
                break;
            }
        }
    }

    public static Skin Skin { get; set; }

Any way, i can offcourse change skin in the config file without recompile but my goal is to be able to change the three files: ..colors.xaml, ...Images.xaml and ...styles.xaml without recompile the project. In my solution it look like this:

Xaml solution files

I want them as content files, and be able to copie to the output somewhere so they can be change without recompilation. Ex ->

<Border x:Name="border" CornerRadius="15" Background="White" BorderBrush="Black" 
BorderThickness="2" >

change CornerRadius to 0 if i dont want any corners on my buttons !

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

If you put a valid uncompiled resource dictionary as a .xaml file in the folder alongside your exe then you can merge it using the same sort of xaml you'd use with a resource dictionary which is compiled into your exe.

Here's app.xaml from the sample I mentioned.

<Application x:Class="Wpf_Dynamic_XAML_FlatResourceDictionary.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                 <ResourceDictionary Source="FlatFile.xaml"/>
                 <ResourceDictionary Source="Dictionary1.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

In the sample FlatFile.xaml is a resource dictionary whose properties are Content and copy if newer.

You could omit that from the solution entirely and copy the resource dictionary manually next to the exe instead and it would still merge.

You may do the equivalent in code.

In the map builder for our game you can choose to merge in an uncompiled .xaml file as a resource dictionary. This then allows you to build content external to the map editor and import into it. The user picks a file name off a list of files in a specific folder. The application has no reference to the content at all and a user can add or remove files externally as they wish.

                 var rdUrl = System.IO.Path.Combine(FilesIO.MapsCustomResourcesFolder, vm.SelectedFile.Name + ".xaml");
                 try
                 {
                     ResourceDictionary rd = new ResourceDictionary();
                     rd.Source = new Uri(rdUrl, UriKind.Absolute);
                     Application.Current.Resources.MergedDictionaries.Add(rd);
                 }
                 catch (Exception ex)
                 {
                     // Some user message stuff
                 }

Bear in mind that if you let the users manually edit a resource dictionary then they could well make changes which break it. An invalid resource dictionary merged in app.xaml will crash your app on load. Code and error trapping can explicitly tell a user they broke their resource dictionary and allow them to carry on using your app.

You could alternatively use XamlReader.Load() to generate a resource dictionary from a file and merge that resource dictionary.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...