Click here to Skip to main content
15,895,667 members
Articles / Desktop Programming / WPF
Tip/Trick

dynamic WPF theme by zip

Rate me:
Please Sign up or sign in to vote.
4.00/5 (1 vote)
31 Mar 2014CPOL2 min read 7.8K   317   3  
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
    C#
    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
    <?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
    C#
    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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
China China
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --