base a style on a Silverlight toolkit theme style

"BasedOn" Styles are existing in SL 3, here is an example (a button style, then a big button style based on the first one) :

<Style x:Key="BaseButton" TargetType="Button">
<Setter Property="Width" Value="90" />
<Setter Property="Height" Value="30" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Bottom" />
<Setter Property="BorderThickness" Value="2"/>
</Style>
<Style x:Key="BigButton" 
         BasedOn="{StaticResource BaseButton}"
         TargetType="Button">
  <Setter Property="Width" Value="180" />
  <Setter Property="Height" Value="60" />
  <Setter Property="FontFamily" Value="Comic Sans MS"/>
</Style>
----------------------------------------
Implicit styles are added to the dictionary using a key equal to their target type. Unfortunately Silverlight 4 does not support the {x:Type} extension so we cannot look them up directly. However, if we duplicate the entries in the dictionary using a string for the key we CAN look them up.
Insert this code before you assign the root visual.
 private void Application_Startup(object sender, StartupEventArgs e)      
{        
 var implicitStyleKeys = Resources.Keys.OfType<Type>().Where(k => typeof(FrameworkElement).IsAssignableFrom(k) &&  Resources[k] is Style);        
 foreach (var implicitStyleKey in implicitStyleKeys)            
  Resources.Add(implicitStyleKey.FullName, Resources[implicitStyleKey]);       
 this.RootVisual = new MainPage();      
}
  
You can now create styles based on you default styles as follows: 
 
 
<Style TargetType="Button" BasedOn="{StaticResource System.Windows.Controls.Button}" / >
 
 
Ok I think I've found a way to do this nicely and even get Blend to play ball at design time! It involves creating a descendent of ResourceDictionary (one of the few non-sealed classes!!)
 that can import the theme and expose its resources by name. 
Below is some sample xaml that uses the technique, notice "Theming:ThemeResourceDictionary".
 This dictionary imports safely (excluding types not found) the theme specified in the ThemeSource property and exposes all default styles by their full type name. 
These styles are then available to the "Button" style declared below. 
 
<ResourceDictionary    
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"     
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"     
  xmlns:Theming="clr-namespace:Samples.Theming;assembly=Samples.Theming">    
  <ResourceDictionary.MergedDictionaries>        
    <Theming:ThemeResourceDictionary ThemeSource="System.Windows.Controls.Theming.ExpressionDark.xaml" />    
  </ResourceDictionary.MergedDictionaries>   
  <Style TargetType="Button" BasedOn="{StaticResource System.Windows.Controls.Button}" />
</ResourceDictionary>
 
Unfortunetly the ThemeSource property is ignored at design time in blend so you won't initially see the magic, 
however, to overcome this the ThemeResourceDictionary looks for a resource called "DefaultDesignThemeUri" at design time. Again the ordering is important, 
the "DefaultDesignThemeUri"  must be secified in a merged dictionary "before" the import of your inherited theme.
<ResourceDictionary>            
  <ResourceDictionary.MergedDictionaries>    
<ResourceDictionary>   
  <!-- Must be declared before inherited to ensure the value is available --> 
  <System:String x:Key="DefaultDesignThemeUri">System.Windows.Controls.Theming.ExpressionDark.xaml</System:String>
</ResourceDictionary>
<ResourceDictionary Source="Inherited.xaml"/> 
</ResourceDictionary.MergedDictionaries> 
</ResourceDictionary>
Once you have done this you shold be able to edit your based on style in blend.
 If you change the "DefaultDesignThemeUri" you may need to close and reopen your page to update the designer.   
 
Here is the code for the classes required. 
public static class ThemeResourceLoader   
{      
/// &lt;summary&gt;      
/// Extends the Theme class      
/// &lt;/summary&gt;      
/// &lt;remarks&gt;     
/// Uses the base implementation to load Dictionaries that may contain references to types not available.
/// &lt;/remarks&gt;      
private class InternalTheme : Theme     
 {        
 private readonly ResourceDictionary _themeResourceDictionary;        
 public InternalTheme(Stream themeResourceStream) : base(themeResourceStream)        
 {            
// get the loaded dictionary          
  _themeResourceDictionary = Resources.MergedDictionaries[0];           
 // remove the dictionary from our resources so it can be re-used.            
Resources.MergedDictionaries.Clear();        
 }        
 public ResourceDictionary ThemeResourceDictionary         
{            
get           
 {               
return _themeResourceDictionary;                
  }        
 }      
}            
public static ResourceDictionary Load(Stream stream)      {         var theme = new InternalTheme(stream);         return theme.ThemeResourceDictionary;      }      
public static ResourceDictionary LoadAndMerge(Stream stream, ResourceDictionary target)      
{         
var themeResourceDictionary = Load(stream);         
target.MergedDictionaries.Clear();        
 target.MergedDictionaries.Add(themeResourceDictionary);         
return themeResourceDictionary;     
 }   
}
   
public class ThemeResourceDictionary : ResourceDictionary  
 {     
 public static readonly DependencyProperty ThemeSourceProperty 
= DependencyProperty.Register(         "ThemeSource", typeof(Uri), typeof(ThemeResourceDictionary), new PropertyMetadata(null, ThemeSourceChanged));      
private ResourceDictionary _themeDictionary;      
public ThemeResourceDictionary()      
{        
 if (DesignerProperties.IsInDesignTool)       
  {           
 var themeUri = Application.Current.Resources["DefaultDesignThemeUri"] as string ?? "DefaultDesignTheme.xaml";            
var themeDictionary = LoadThemeDictionary(new Uri(themeUri, UriKind.Relative));          
  if (themeDictionary != null)              
 MergeThemeDictionary(themeDictionary);       
  }     
 }            
public Uri ThemeSource      {         get         {            return (Uri)GetValue(ThemeSourceProperty);         }         set         {            SetValue(ThemeSourceProperty, value);         }      }     
 private static void ThemeSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)    
  {         
var newValue = (Uri)e.NewValue;        
 var oldValue = (Uri)e.OldValue;        
 if (newValue != oldValue)           
 ((ThemeResourceDictionary)d).ThemeSourceChanged(oldValue, newValue);      
}     
 private void ThemeSourceChanged(Uri oldValue, Uri newValue)     
 {        
 RemoveCurrentThemeDictionary();       
  if (newValue != null)        
 {            
var themeDictionary = LoadThemeDictionary(newValue);          
  if (themeDictionary != null)             
  MergeThemeDictionary(themeDictionary);        
 }      
}      
private void MergeThemeDictionary(ResourceDictionary themeDictionary)      
{         
MergedDictionaries.Add(themeDictionary);        
 // add a string entry for every "default" style matching the FullName of the type         
foreach (var item in themeDictionary.Where(entry => entry.Key is Type && entry.Value is Style).ToList())            
this.Add(((Type)item.Key).FullName, item.Value);        
 _themeDictionary = themeDictionary;      
}      
private static ResourceDictionary LoadThemeDictionary(Uri source)     
 {         
var streamResourceInfo = Application.GetResourceStream(source);         
if (streamResourceInfo == null)           
 return null;         
return ThemeResourceLoader.Load(streamResourceInfo.Stream);     
 }     
 private void RemoveCurrentThemeDictionary()    
  {        
 if (_themeDictionary != null)       
  {           
 MergedDictionaries.Remove(_themeDictionary);           
 _themeDictionary = null;        
 }      
}   
}
posted @ 2010-11-30 21:52  不弃的追求  阅读(462)  评论(0编辑  收藏  举报