Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

dynamic WPF theme by zip

0.00/5 (No votes)
31 Mar 2014 1  
dynamic WPF theme by zip

Introduction

WPF provide many ways to theme the application, i provide a new way to theme the application dynamically, neither AppDomain, nor loose xaml

Background

Make sure you are familar with the common WPF theme, maybe you can refer to the other great article at first

Using the code

Before present my theme way, let's see what's cons & pros on the classic theme way

Theme strategy

Load Speed

Native support( not require additional code)

Support code themed(bundle code & resource into single file)

Support resource hierarchy navigation

Load dynamically

Unload dynamically

Easily edit and compile(not require VS installed)

Direct Load

Fast

Y

Y

Y

Y

N

N

Loose Xaml

Low

Y

N

Y

Y

Y

Y

AppDomain

Fast

N

Y

N

Y

Y

N

Let's see some fact

  • Xaml support pack protocol Uri
  • pack protocol support custom parser( System.IO.Packaging.PackageStore)
  • WPF support Zip file parser ( System.IO.Packaging.ZipPackage)

Now let's combine these fact into a new theme way

  1. add/remove custom parser for pack protocol
              PackageStore.AddPackage(new Uri("customtheme://"), Package.Open("123.zip"));
              PackageStore.RemovePackage(new Uri("customtheme://")); 
  2. embed resources files/folders to single zip file, i use the 7za.exe (from 7zip command line tools )

    7za.exe

    a

    -tzip

    theme1.customtheme

    .\Themes\theme1\*

    -mm=copy

    Add/ Replace files in zip

    Use zip compress algorithm

    Destination zip file, extension can be changed

    The source files to compressed

    The compress strategy, just copy , don’t do compress to improve the decompress speed

  3. Because ZipPackage is designed for XPS, and XPS require to include a file named [Content_types].xml to identify the content type, so make sure always present a valid [Content_types].xml besides the resource files in the destination zip file
    <?xml version="1.0" encoding="utf-8" ?>
    <Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
      <Default Extension="png" ContentType="image/png" />
      <Default Extension="tiff" ContentType="image/tiff" />
      <Default Extension="jpg" ContentType="image/jpeg" />
      <Default Extension="gif" ContentType="image/gif" />
      <Default Extension="bmp" ContentType="image/bmp" />
      <Default Extension="txt" ContentType="text/plain" />
      <Default Extension="xaml" ContentType="application/xaml+xml" />
      <Default Extension="xml" ContentType="application/xml" />
      <Default Extension="avi" ContentType="video/avi" />
      <Default Extension="mp4" ContentType="video/mp4" />
      <Default Extension="mp3" ContentType="audio/mp3" />
    </Types> 
  4. i use MemoryMappedFile to improve IO access speed, because there are many little-size IO access when Xaml load theme files
        Stream fileMapViewStream;
        try
        {
            fileMapViewStream = MemoryMappedFile.OpenExisting(item.Replace("\\", ":"), MemoryMappedFileRights.Read).CreateViewStream(0, new FileInfo(item).Length, MemoryMappedFileAccess.Read);
        }
        catch(IOException)
        {
            fileMapViewStream = MemoryMappedFile.CreateFromFile(item, FileMode.Open, item.Replace("\\", ":"), new FileInfo(item).Length, MemoryMappedFileAccess.Read).CreateViewStream(0, new FileInfo(item).Length, MemoryMappedFileAccess.Read); 
        }
    
  5. At last, we got the most important code for this article
          private void cmbThemes_SelectionChanged(object sender, SelectionChangedEventArgs e)
            {
                if (e.RemovedItems != null)
                {
                    foreach (var item in e.RemovedItems.OfType<string>())
                    {
                        PackageStore.RemovePackage(new Uri(System.IO.Path.GetFileName(item) + "://"));                                       
                    }
                }
    
    
    
    
                if (e.AddedItems != null)
                {
                    foreach (var item in e.AddedItems.OfType<string>())
                    {
                        Stream fileMapViewStream;
                        try
                        {
                            fileMapViewStream = MemoryMappedFile.OpenExisting(item.Replace("\\", ":"), MemoryMappedFileRights.Read).CreateViewStream(0, new FileInfo(item).Length, MemoryMappedFileAccess.Read);
                        }
                        catch(IOException)
                        {
                            fileMapViewStream = MemoryMappedFile.CreateFromFile(item, FileMode.Open, item.Replace("\\", ":"), new FileInfo(item).Length, MemoryMappedFileAccess.Read).CreateViewStream(0, new FileInfo(item).Length, MemoryMappedFileAccess.Read); 
                        }
                        PackageStore.AddPackage(new Uri(System.IO.Path.GetFileName(item) + "://"), Package.Open(fileMapViewStream, FileMode.Open, FileAccess.Read));
                        Application.Current.Resources.MergedDictionaries[0] = new ResourceDictionary() { Source = new Uri("pack://" + System.IO.Path.GetFileName(item) + ":,,,/ResourceDictionary.xaml") };
                    }
                }
            }
    

At last, let's see the comparison between the three classic theme ways

Theme strategy

Load Speed

Native support( not require additional code)

Support code themed(bundle code & resource into single file)

Support resource hierarchy navigation

Load dynamically

Unload dynamically

Easily edit and compile(not require VS installed)

Direct Load

Fast

Y

Y

Y

Y

N

N

Loose Xaml

Low

Y

N

Y

Y

Y

Y

AppDomain

Fast

N

Y

N

Y

Y

N

Zip file

Fast(*)

N

N

Y

Y

Y

Y

* Though Zip file don't compile the Xaml to baml, but consider the MemoryMappedFile, so will require less IO operation theoretically, speed should be fasterSmile | :)

History

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here