欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

WPF换肤设计原理浅析

程序员文章站 2022-03-10 14:31:01
wpf换肤的设计原理,利用资源字典为每种皮肤资源添加不同的样式,在后台切换皮肤资源文件。 截图 上图中,第一张图采用规则样式,第二张图采用不规则样式,截图的时候...

wpf换肤的设计原理,利用资源字典为每种皮肤资源添加不同的样式,在后台切换皮肤资源文件。

截图

WPF换肤设计原理浅析

上图中,第一张图采用规则样式,第二张图采用不规则样式,截图的时候略有瑕疵。

资源字典

规则样式资源skin.regularstyle.xaml

<resourcedictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

 <!--window样式-->
 <style x:key="windowstyle" targettype="window">
  <setter property="template">
   <setter.value>
    <controltemplate targettype="window">
     <border borderbrush="{templatebinding borderbrush}" 
       borderthickness="{templatebinding borderthickness}">
      <border.background>
       <lineargradientbrush startpoint="0,0" endpoint="0,1">
        <gradientstop color="green" offset="0"></gradientstop>
        <gradientstop color="lightgreen" offset="0.4"></gradientstop>
        <gradientstop color="white" offset="1"></gradientstop>
       </lineargradientbrush>
      </border.background>
      <contentpresenter></contentpresenter>
     </border>
    </controltemplate>
   </setter.value>
  </setter>
 </style>

 <!--button样式-->
 <style targettype="button">
  <setter property="width" value="70"></setter>
  <setter property="height" value="23"></setter>
  <setter property="template">
   <setter.value>
    <controltemplate targettype="button">
     <border name="bdr" cursor="arrow"
       borderbrush="{templatebinding borderbrush}" 
       borderthickness="{templatebinding borderthickness}">
      <border.background>
       <lineargradientbrush startpoint="0,0" endpoint="0,1">
        <gradientstop color="white" offset="0"></gradientstop>
        <gradientstop color="lightgreen" offset="0.3"></gradientstop>
        <gradientstop color="green" offset="1"></gradientstop>
       </lineargradientbrush>
      </border.background>
      <textblock name="tbk" background="transparent" foreground="darkgreen" textalignment="center"
         text="{templatebinding content}"></textblock>
     </border>
     <controltemplate.triggers>
      <trigger property="ismouseover" value="true">
       <setter targetname="bdr" property="background">
        <setter.value>
         <lineargradientbrush startpoint="0,0" endpoint="0,1">
          <gradientstop color="lightgreen" offset="0"></gradientstop>
          <gradientstop color="green" offset="1"></gradientstop>
         </lineargradientbrush>
        </setter.value>
       </setter>
       <setter targetname="tbk" property="foreground" value="white"></setter>
      </trigger>
     </controltemplate.triggers>
    </controltemplate>
   </setter.value>
  </setter>
 </style>

 <!--textbox样式-->
 <style targettype="textbox">
  <setter property="fontfamily" value="sketchflow print"/>
  <setter property="fontsize" value="14"/>
  <setter property="template">
   <setter.value>
    <controltemplate targettype="textbox">
     <border borderbrush="darkgreen" borderthickness="0.5">
      <scrollviewer x:name="part_contenthost" focusable="false" 
          horizontalscrollbarvisibility="hidden" 
          verticalscrollbarvisibility="hidden"></scrollviewer>
     </border>
    </controltemplate>
   </setter.value>
  </setter>
 </style>

 <!--contextmenu样式-->
 <style targettype="contextmenu">
  <setter property="template">
   <setter.value>
    <controltemplate targettype="contextmenu">
     <border borderbrush="green" borderthickness="1">
      <itemspresenter/>
     </border>
    </controltemplate>
   </setter.value>
  </setter>
 </style>

 <!--menuitem样式-->
 <style targettype="menuitem">
  <setter property="template">
   <setter.value>
    <controltemplate targettype="menuitem">
     <border name="border" background="lightgreen" borderthickness="0">
      <textblock name="tbk" background="transparent" padding="5,5"
         text="{templatebinding header}"></textblock>
     </border>
     <controltemplate.triggers>
      <trigger property="ismouseover" value="true">
       <setter targetname="border" property="background" value="green"></setter>
       <setter targetname="tbk" property="foreground" value="white"></setter>
      </trigger>
     </controltemplate.triggers>
    </controltemplate>
   </setter.value>
  </setter>
 </style>

 <!--textblock样式-->
 <style targettype="textblock">
  <setter property="fontfamily" value="sketchflow print"/>
  <setter property="fontsize" value="14"/>
 </style>

</resourcedictionary>
不规则样式资源skin.roundedcornerstyle.xaml
<resourcedictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

 <!--window样式-->
 <style x:key="windowstyle" targettype="window">
  <setter property="template">
   <setter.value>
    <controltemplate targettype="window">
     <grid margin="10">
      <rectangle fill="{dynamicresource {x:static systemcolors.windowbrushkey}}" 
         radiusx="5" radiusy="5">
       <rectangle.effect>
        <dropshadoweffect blurradius="10" color="black" direction="0" opacity="0.8"
             renderingbias="performance" shadowdepth="0"/>
       </rectangle.effect>
      </rectangle>
      <border borderbrush="{templatebinding borderbrush}" 
        borderthickness="{templatebinding borderthickness}" 
        snapstodevicepixels="true" cornerradius="5">
       <border.background>
        <lineargradientbrush startpoint="0,0" endpoint="0,1">
         <gradientstop color="blue" offset="0"></gradientstop>
         <gradientstop color="lightblue" offset="0.4"></gradientstop>
         <gradientstop color="white" offset="1"></gradientstop>
        </lineargradientbrush>
       </border.background>
       <contentpresenter></contentpresenter>
      </border>
     </grid>
    </controltemplate>
   </setter.value>
  </setter>
 </style>
 
 <!--button样式-->
 <style targettype="button">
  <setter property="width" value="70"></setter>
  <setter property="height" value="23"></setter>
  <setter property="template">
   <setter.value>
    <controltemplate targettype="button">
     <border name="bdr" cornerradius="5" cursor="hand"
       borderbrush="{templatebinding borderbrush}" 
       borderthickness="{templatebinding borderthickness}">
      <textblock name="tbk" background="transparent" foreground="yellow" textalignment="center"
         text="{binding relativesource={relativesource templatedparent},path=content}"></textblock>
      <border.background>
       <lineargradientbrush startpoint="0,0" endpoint="0,1">
        <gradientstop color="white" offset="0"></gradientstop>
        <gradientstop color="lightblue" offset="0.3"></gradientstop>
        <gradientstop color="blue" offset="1"></gradientstop>
       </lineargradientbrush>
      </border.background>
     </border>
     <controltemplate.triggers>
      <trigger property="ismouseover" value="true">
       <setter targetname="bdr" property="background">
        <setter.value>
         <lineargradientbrush startpoint="0,0" endpoint="0,1">
          <gradientstop color="lightblue" offset="0"></gradientstop>
          <gradientstop color="blue" offset="1"></gradientstop>
         </lineargradientbrush>
        </setter.value>
       </setter>
       <setter targetname="tbk" property="foreground" value="lightyellow"></setter>
      </trigger>
     </controltemplate.triggers>
    </controltemplate>
   </setter.value>
  </setter>
 </style>

 <!--textbox样式-->
 <style targettype="textbox">
  <setter property="fontfamily" value="times new roman"></setter>
  <setter property="fontsize" value="14"></setter>
  <setter property="template">
   <setter.value>
    <controltemplate targettype="textbox">
     <border borderbrush="blue" borderthickness="0.5" cornerradius="5">
      <scrollviewer x:name="part_contenthost" focusable="false" 
          horizontalscrollbarvisibility="hidden" 
          verticalscrollbarvisibility="hidden"></scrollviewer>
     </border>
    </controltemplate>
   </setter.value>
  </setter>
 </style>

 <!--contextmenu样式-->
 <style targettype="contextmenu">
  <setter property="template">
   <setter.value>
    <controltemplate targettype="contextmenu">
     <border cornerradius="5" borderbrush="blue" borderthickness="1">
      <itemspresenter/>
     </border>
    </controltemplate>
   </setter.value>
  </setter>
 </style>

 <!--menuitem样式-->
 <style targettype="menuitem">
  <setter property="template">
   <setter.value>
    <controltemplate targettype="menuitem">
     <border name="border" background="lightskyblue" borderthickness="0" cornerradius="5">
      <textblock name="tbk" background="transparent" padding="5,5"
         text="{templatebinding header}"></textblock>
     </border>
     <controltemplate.triggers>
      <trigger property="ismouseover" value="true">
       <setter targetname="border" property="background" value="blueviolet"></setter>
       <setter targetname="tbk" property="foreground" value="white"></setter>
      </trigger>
     </controltemplate.triggers>
    </controltemplate>
   </setter.value>
  </setter>
 </style>
 
 <!--textblock样式-->
 <style targettype="textblock">
  <setter property="fontfamily" value="times new roman"/>
  <setter property="fontsize" value="14"/>
 </style>
</resourcedictionary>

仔细观察上面定义的样式,你会发现在定义window样式的时候指定了key,其他的control样式却没有指定key。大家都知道,如果没有给style指定key,那么这个style会应用到所有目标类型(targettype)为指定类型的control。请看下面一段文字:

WPF换肤设计原理浅析

因为在换肤的过程中,需要动态加载window的样式,所以用dynamicresource作绑定style="{dynamicresource windowstyle}"。

app.xaml

程序运行的时候,默认加载规则样式的皮肤。

<application.resources>
  <resourcedictionary>
   <resourcedictionary.mergeddictionaries>
    <resourcedictionary source="dictionary\skin.regularstyle.xaml"></resourcedictionary>
   </resourcedictionary.mergeddictionaries>
  </resourcedictionary>
 </application.resources>

后台代码

/// <summary>
  /// menuitem的执行方法
  /// </summary>
  /// <param name="parameter"></param>
  private void relaymenuitemevent(object parameter)
  {
   if (parameter.tostring() == regularstyle)
   {
    changeskinresource(skins[0]);
   }
   else if (parameter.tostring() == roundedcornerstyle)
   {
    changeskinresource(skins[1]);
   }
  }

  /// <summary>
  /// 更换皮肤资源
  /// </summary>
  /// <param name="skin"></param>
  private void changeskinresource(resourcedictionary skin)
  {
   if (application.current.resources.mergeddictionaries[0].source.isabsoluteuri)
   {
    if (application.current.resources.mergeddictionaries[0].source.originalstring != skin.source.originalstring)
    {
     application.current.resources.mergeddictionaries[0] = skin;
    }
   }
   else
   {
    if (application.current.resources.mergeddictionaries[0].source.originalstring.tostring('\\') != skin.source.originalstring.tostring('/'))
    {
     application.current.resources.mergeddictionaries[0] = skin;
    }
   }
  }

运行的时候在mainwindow上右键选择皮肤样式,就可以换肤了。

源码下载:http://xiazai.jb51.net/201610/yuanma/wpfskin(jb51.net).rar

链接:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。