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

超炫酷的WPF实现Loading控件效果

程序员文章站 2022-07-06 12:43:00
win8系统的loading效果还是很不错的,网上也有人用css3等技术实现,研究了一下,并打算用wpf自定义一个loading控件实现类似的效果,并可以让用户对loadi...

win8系统的loading效果还是很不错的,网上也有人用css3等技术实现,研究了一下,并打算用wpf自定义一个loading控件实现类似的效果,并可以让用户对loading的颗粒(particle)背景颜色进行自定义,话不多说,直接上代码:

1、用vs2012新建一个wpf的用户控件库项目wpfcontrollibrarydemo,vs自动生成如下结构:

超炫酷的WPF实现Loading控件效果

2、删除usercontrol1.xaml,并新建一个loading的customcontrol(不是usercontrol),如下图所示:

超炫酷的WPF实现Loading控件效果

3、如果报错找不到loading类型,请编译,下面在generic.xaml主题文件中对loading的样式和内容进行定义(注意添加

xmlns:system = "clr-namespace:system;assembly=mscorlib"),代码如下:
<resourcedictionary
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:system = "clr-namespace:system;assembly=mscorlib"
 xmlns:local="clr-namespace:wpfcontrollibrarydemo">


 <style targettype="{x:type local:loading}">
 <setter property="template">
  <setter.value>
  <controltemplate targettype="{x:type local:loading}">
   <border background="{templatebinding background}"
    borderbrush="{templatebinding borderbrush}"
    borderthickness="{templatebinding borderthickness}">
   <grid width = "50" height = "50">
    <grid.resources>
    <!-- value converters -->
    
    <!-- particle styling ,must to has relativesource -->
    <solidcolorbrush x:key = "particlecolor" color = "{binding path=fillcolor,relativesource={relativesource templatedparent}}" />
    <solidcolorbrush x:key = "particlebackgroundcolor" color = "transparent"/>
    <system:double x:key = "particleopacity">1</system:double>
    <system:double x:key = "particleradius">5</system:double>

    <system:double x:key = "startingpointx">0</system:double>
    <system:double x:key = "startingpointy">-20</system:double>

    <system:double x:key = "rotationpointx">0.5</system:double>
    <system:double x:key = "rotationpointy">0.5</system:double>

    <!-- storyboard -->
    <system:timespan x:key = "storyboardbegintimep0">00:00:00.000</system:timespan>
    <system:timespan x:key = "storyboardbegintimep1">00:00:00.100</system:timespan>
    <system:timespan x:key = "storyboardbegintimep2">00:00:00.200</system:timespan>
    <system:timespan x:key = "storyboardbegintimep3">00:00:00.300</system:timespan>
    <system:timespan x:key = "storyboardbegintimep4">00:00:00.400</system:timespan>
    <duration x:key = "storyboardduration">00:00:01.800</duration>

    <!-- particle origin angles -->
    <system:double x:key = "particleoriginanglep0">0</system:double>
    <system:double x:key = "particleoriginanglep1">-10</system:double>
    <system:double x:key = "particleoriginanglep2">-20</system:double>
    <system:double x:key = "particleoriginanglep3">-30</system:double>
    <system:double x:key = "particleoriginanglep4">-40</system:double>

    <!-- particle position & timing 1 -->
    <system:double x:key = "particlebeginangle1">0</system:double>
    <system:double x:key = "particleendangle1">90</system:double>
    <system:timespan x:key = "particlebegintime1">00:00:00.000</system:timespan>
    <duration x:key = "particleduration1">00:00:00.750</duration>

    <!-- particle position & timing 2 -->
    <system:double x:key = "particlebeginangle2">90</system:double>
    <system:double x:key = "particleendangle2">270</system:double>
    <system:timespan x:key = "particlebegintime2">00:00:00.751</system:timespan>
    <duration x:key = "particleduration2">00:00:00.300</duration>

    <!-- particle position & timing 3 -->
    <system:double x:key = "particlebeginangle3">270</system:double>
    <system:double x:key = "particleendangle3">360</system:double>
    <system:timespan x:key = "particlebegintime3">00:00:01.052</system:timespan>
    <duration x:key = "particleduration3">00:00:00.750</duration>

    <style x:key = "ellipsestyle" targettype = "ellipse">
     <setter property = "width" value = "{staticresource particleradius}"/>
     <setter property = "height" value = "{staticresource particleradius}"/>
     <setter property = "fill" value = "{staticresource particlecolor}"/>
     <setter property = "rendertransformorigin" value = "0.5, 0.5"/>
     <setter property = "opacity" value = "{staticresource particleopacity}"/>
    </style>
    </grid.resources>
    <canvas width = "1" height = "1" margin="0,0,0,0">
    <canvas.triggers>
     <eventtrigger routedevent = "canvas.loaded">
     <eventtrigger.actions>
      <beginstoryboard>
      <storyboard
    
    begintime = "{staticresource storyboardbegintimep0}"
    duration = "{staticresource storyboardduration}"
    repeatbehavior = "forever">
       <doubleanimation
    storyboard.targetname = "p0"
    storyboard.targetproperty = "(uielement.rendertransform).(rotatetransform.angle)"
    from = "{staticresource particlebeginangle1}"
    to = "{staticresource particleendangle1}"
    begintime = "{staticresource particlebegintime1}"
    duration = "{staticresource particleduration1}"/>
       <doubleanimation
    storyboard.targetname = "p0"
    storyboard.targetproperty = "(uielement.rendertransform).(rotatetransform.angle)"
    from = "{staticresource particlebeginangle2}"
    to = "{staticresource particleendangle2}"
    begintime = "{staticresource particlebegintime2}"
    duration = "{staticresource particleduration2}"/>
       <doubleanimation
    storyboard.targetname = "p0"
    storyboard.targetproperty = "(uielement.rendertransform).(rotatetransform.angle)"
    from = "{staticresource particlebeginangle3}"
    to = "{staticresource particleendangle3}"
    begintime = "{staticresource particlebegintime3}"
    duration = "{staticresource particleduration3}"/>
      </storyboard>
      </beginstoryboard>
      <beginstoryboard>
      <storyboard
    
    begintime = "{staticresource storyboardbegintimep1}"
    duration = "{staticresource storyboardduration}"
    repeatbehavior = "forever">

       <doubleanimation
    storyboard.targetname = "p1"
    storyboard.targetproperty = "(uielement.rendertransform).(rotatetransform.angle)"
    from = "{staticresource particlebeginangle1}"
    to = "{staticresource particleendangle1}"
    begintime = "{staticresource particlebegintime1}"
    duration = "{staticresource particleduration1}"/>
       <doubleanimation
    storyboard.targetname = "p1"
    storyboard.targetproperty = "(uielement.rendertransform).(rotatetransform.angle)"
    from = "{staticresource particlebeginangle2}"
    to = "{staticresource particleendangle2}"
    begintime = "{staticresource particlebegintime2}"
    duration = "{staticresource particleduration2}"/>
       <doubleanimation
    storyboard.targetname = "p1"
    storyboard.targetproperty = "(uielement.rendertransform).(rotatetransform.angle)"
    from = "{staticresource particlebeginangle3}"
    to = "{staticresource particleendangle3}"
    begintime = "{staticresource particlebegintime3}"
    duration = "{staticresource particleduration3}"/>
      </storyboard>
      </beginstoryboard>
      <beginstoryboard>
      <storyboard
    
    begintime = "{staticresource storyboardbegintimep2}"
    duration = "{staticresource storyboardduration}"
    repeatbehavior = "forever">

       <doubleanimation
    storyboard.targetname = "p2"
    storyboard.targetproperty = "(uielement.rendertransform).(rotatetransform.angle)"
    from = "{staticresource particlebeginangle1}"
    to = "{staticresource particleendangle1}"
    begintime = "{staticresource particlebegintime1}"
    duration = "{staticresource particleduration1}"/>
       <doubleanimation
    storyboard.targetname = "p2"
    storyboard.targetproperty = "(uielement.rendertransform).(rotatetransform.angle)"
    from = "{staticresource particlebeginangle2}"
    to = "{staticresource particleendangle2}"
    begintime = "{staticresource particlebegintime2}"
    duration = "{staticresource particleduration2}"/>
       <doubleanimation
    storyboard.targetname = "p2"
    storyboard.targetproperty = "(uielement.rendertransform).(rotatetransform.angle)"
    from = "{staticresource particlebeginangle3}"
    to = "{staticresource particleendangle3}"
    begintime = "{staticresource particlebegintime3}"
    duration = "{staticresource particleduration3}"/>
      </storyboard>
      </beginstoryboard>

      <beginstoryboard>
      <storyboard
    
    begintime = "{staticresource storyboardbegintimep3}"
    duration = "{staticresource storyboardduration}"
    repeatbehavior = "forever">

       <doubleanimation
    storyboard.targetname = "p3"
    storyboard.targetproperty = "(uielement.rendertransform).(rotatetransform.angle)"
    from = "{staticresource particlebeginangle1}"
    to = "{staticresource particleendangle1}"
    begintime = "{staticresource particlebegintime1}"
    duration = "{staticresource particleduration1}"/>
       <doubleanimation
    storyboard.targetname = "p3"
    storyboard.targetproperty = "(uielement.rendertransform).(rotatetransform.angle)"
    from = "{staticresource particlebeginangle2}"
    to = "{staticresource particleendangle2}"
    begintime = "{staticresource particlebegintime2}"
    duration = "{staticresource particleduration2}"/>
       <doubleanimation
    storyboard.targetname = "p3"
    storyboard.targetproperty = "(uielement.rendertransform).(rotatetransform.angle)"
    from = "{staticresource particlebeginangle3}"
    to = "{staticresource particleendangle3}"
    begintime = "{staticresource particlebegintime3}"
    duration = "{staticresource particleduration3}"/>
      </storyboard>
      </beginstoryboard>

      <beginstoryboard>
      <storyboard
    
    begintime = "{staticresource storyboardbegintimep4}"
    duration = "{staticresource storyboardduration}"
    repeatbehavior = "forever">

       <doubleanimation
    storyboard.targetname = "p4"
    storyboard.targetproperty = "(uielement.rendertransform).(rotatetransform.angle)"
    from = "{staticresource particlebeginangle1}"
    to = "{staticresource particleendangle1}"
    begintime = "{staticresource particlebegintime1}"
    duration = "{staticresource particleduration1}"/>
       <doubleanimation
    storyboard.targetname = "p4"
    storyboard.targetproperty = "(uielement.rendertransform).(rotatetransform.angle)"
    from = "{staticresource particlebeginangle2}"
    to = "{staticresource particleendangle2}"
    begintime = "{staticresource particlebegintime2}"
    duration = "{staticresource particleduration2}"/>
       <doubleanimation
    storyboard.targetname = "p4"
    storyboard.targetproperty = "(uielement.rendertransform).(rotatetransform.angle)"
    from = "{staticresource particlebeginangle3}"
    to = "{staticresource particleendangle3}"
    begintime = "{staticresource particlebegintime3}"
    duration = "{staticresource particleduration3}"/>
      </storyboard>
      </beginstoryboard>
     </eventtrigger.actions>
     </eventtrigger>
    </canvas.triggers>
    <border
  x:name = "p0"
  background = "{staticresource particlebackgroundcolor}"
  opacity = "{staticresource particleopacity}">
     <border.rendertransform>
     <rotatetransform/>
     </border.rendertransform>
     <border.rendertransformorigin>
     <point x = "{staticresource rotationpointx}" y = "{staticresource rotationpointy}"/>
     </border.rendertransformorigin>
     <ellipse style = "{staticresource ellipsestyle}">
     <ellipse.rendertransform>
      <transformgroup>
      <translatetransform x = "{staticresource startingpointx}" y = "{staticresource startingpointy}"/>
      <rotatetransform angle = "{staticresource particleoriginanglep0}"/>
      </transformgroup>
     </ellipse.rendertransform>
     </ellipse>
    </border>
    <border
  x:name = "p1"
  background = "{staticresource particlebackgroundcolor}"
  opacity = "{staticresource particleopacity}">
     <border.rendertransform>
     <rotatetransform/>
     </border.rendertransform>
     <border.rendertransformorigin>
     <point x = "{staticresource rotationpointx}" y = "{staticresource rotationpointy}"/>
     </border.rendertransformorigin>
     <ellipse style = "{staticresource ellipsestyle}">
     <ellipse.rendertransform>
      <transformgroup>
      <translatetransform x = "{staticresource startingpointx}" y = "{staticresource startingpointy}"/>
      <rotatetransform angle = "{staticresource particleoriginanglep1}"/>
      </transformgroup>
     </ellipse.rendertransform>
     </ellipse>
    </border>
    <border
  x:name = "p2"
  background = "{staticresource particlebackgroundcolor}"
  opacity = "{staticresource particleopacity}">
     <border.rendertransform>
     <rotatetransform/>
     </border.rendertransform>
     <border.rendertransformorigin>
     <point x = "{staticresource rotationpointx}" y = "{staticresource rotationpointy}"/>
     </border.rendertransformorigin>
     <ellipse style = "{staticresource ellipsestyle}">
     <ellipse.rendertransform>
      <transformgroup>
      <translatetransform x = "{staticresource startingpointx}" y = "{staticresource startingpointy}"/>
      <rotatetransform angle = "{staticresource particleoriginanglep2}"/>
      </transformgroup>
     </ellipse.rendertransform>
     </ellipse>
    </border>
    <border
  x:name = "p3"
  background = "{staticresource particlebackgroundcolor}"
  opacity = "{staticresource particleopacity}">
     <border.rendertransform>
     <rotatetransform/>
     </border.rendertransform>
     <border.rendertransformorigin>
     <point x = "{staticresource rotationpointx}" y = "{staticresource rotationpointy}"/>
     </border.rendertransformorigin>
     <ellipse style = "{staticresource ellipsestyle}">
     <ellipse.rendertransform>
      <transformgroup>
      <translatetransform x = "{staticresource startingpointx}" y = "{staticresource startingpointy}"/>
      <rotatetransform angle = "{staticresource particleoriginanglep3}"/>
      </transformgroup>
     </ellipse.rendertransform>
     </ellipse>
    </border>
    <border
  x:name = "p4"
  background = "{staticresource particlebackgroundcolor}"
  opacity = "{staticresource particleopacity}">
     <border.rendertransform>
     <rotatetransform/>
     </border.rendertransform>
     <border.rendertransformorigin>
     <point x = "{staticresource rotationpointx}" y = "{staticresource rotationpointy}"/>
     </border.rendertransformorigin>
     <ellipse style = "{staticresource ellipsestyle}">
     <ellipse.rendertransform>
      <transformgroup>
      <translatetransform x = "{staticresource startingpointx}" y = "{staticresource startingpointy}"/>
      <rotatetransform angle = "{staticresource particleoriginanglep4}"/>
      </transformgroup>
     </ellipse.rendertransform>
     </ellipse>
    </border>
    </canvas>
   </grid>



   </border>
  </controltemplate>
  </setter.value>
 </setter>
 </style>
 
 
 
</resourcedictionary>

在构建中发现,一开始在设定绑定时,写成<solidcolorbrush x:key = "particlecolor" color = "{binding path=fillcolor}" />一直都无法绑定成功,后来查了资料,改成<solidcolorbrush x:key = "particlecolor" color = "{binding path=fillcolor,relativesource={relativesource templatedparent}}" /> 后成功。

4、编辑loading.cs文件,对自定义属性fillcolor和逻辑进行编码:

using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.threading.tasks;
using system.windows;
using system.windows.controls;
using system.windows.data;
using system.windows.documents;
using system.windows.input;
using system.windows.media;
using system.windows.media.imaging;
using system.windows.navigation;
using system.windows.shapes;

namespace wpfcontrollibrarydemo
{
 using system.componentmodel;
 /// <summary>
 /// 按照步骤 1a 或 1b 操作,然后执行步骤 2 以在 xaml 文件中使用此自定义控件。
 ///
 /// 步骤 1a) 在当前项目中存在的 xaml 文件中使用该自定义控件。
 /// 将此 xmlnamespace 特性添加到要使用该特性的标记文件的根 
 /// 元素中:
 ///
 /// xmlns:mynamespace="clr-namespace:wpfcontrollibrarydemo"
 ///
 ///
 /// 步骤 1b) 在其他项目中存在的 xaml 文件中使用该自定义控件。
 /// 将此 xmlnamespace 特性添加到要使用该特性的标记文件的根 
 /// 元素中:
 ///
 /// xmlns:mynamespace="clr-namespace:wpfcontrollibrarydemo;assembly=wpfcontrollibrarydemo"
 ///
 /// 您还需要添加一个从 xaml 文件所在的项目到此项目的项目引用,
 /// 并重新生成以避免编译错误:
 ///
 /// 在解决方案资源管理器中右击目标项目,然后依次单击
 /// “添加引用”->“项目”->[浏览查找并选择此项目]
 ///
 ///
 /// 步骤 2)
 /// 继续操作并在 xaml 文件中使用控件。
 ///
 /// <mynamespace:loading/>
 ///
 /// </summary>
 public class loading : control
 {
 static loading()
 {
  //重载默认样式
  defaultstylekeyproperty.overridemetadata(typeof(loading), new frameworkpropertymetadata(typeof(loading)));
  //dependencyproperty 注册 fillcolor
  fillcolorproperty = dependencyproperty.register("fillcolor",
  typeof(color),
  typeof(loading),
  new uipropertymetadata(colors.darkblue,
  new propertychangedcallback(onurichanged))
  );
  //colors.darkblue为控件初始化默认值

 }
 //属性变更回调函数
 private static void onurichanged(dependencyobject d, dependencypropertychangedeventargs e)
 {
  //border b = (border)d;
  //messagebox.show(e.newvalue.tostring());

 }
 #region 自定义fields
 // dependencyproperty属性定义 fillcolorproperty=fillcolor+property组成
 public static readonly dependencyproperty fillcolorproperty;
 #endregion
 //vs设计器属性支持
 [description("背景色"), category("个性配置"), defaultvalue("#ff668899")]
 public color fillcolor
 {
  //getvalue,setvalue为固定写法,此处一般不建议处理其他逻辑
  get { return (color)getvalue(fillcolorproperty); }
  set { setvalue(fillcolorproperty, value); }
 }
 }
}

 5、编译,如果无误后,可以添加wpf应用程序wpfapploadingtest进行测试(添加项目引用)。

超炫酷的WPF实现Loading控件效果

打开mainwindow.xaml,将loading控件拖放到设计界面上,如下图所示:

超炫酷的WPF实现Loading控件效果

 6、控件颜色修改,选中控件,在属性栏中进行配置即可:

超炫酷的WPF实现Loading控件效果

 7.总结

可以看到wpf自定义控件还是比较容易的,但是难点在于ui的设计,如果需要做的美观,需要美工的参与,而且需要转换成xaml。

以上就是wpf实现炫酷loading控件的全部内容,希望对大家的学习有所帮助。