win8系统的loading效果还是很不错的,网上也有人用css3等技术实现,研究了一下,并打算用wpf自定义一个loading控件实现类似的效果,并可以让用户对loading的颗粒(particle)背景颜色进行自定义,话不多说,直接上代码:
1、用vs2012新建一个wpf的用户控件库项目wpfcontrollibrarydemo,vs自动生成如下结构:
2、删除usercontrol1.xaml,并新建一个loading的customcontrol(不是usercontrol),如下图所示:
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" >0.000</system:timespan>
<system:timespan x:key = "storyboardbegintimep1" >0.100</system:timespan>
<system:timespan x:key = "storyboardbegintimep2" >0.200</system:timespan>
<system:timespan x:key = "storyboardbegintimep3" >0.300</system:timespan>
<system:timespan x:key = "storyboardbegintimep4" >0.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" >0.000</system:timespan>
<duration x:key = "particleduration1" >0.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" >0.751</system:timespan>
<duration x:key = "particleduration2" >0.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" >0.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进行测试(添加项目引用)。
打开mainwindow.xaml,将loading控件拖放到设计界面上,如下图所示:
6、控件颜色修改,选中控件,在属性栏中进行配置即可:
7.总结
可以看到wpf自定义控件还是比较容易的,但是难点在于ui的设计,如果需要做的美观,需要美工的参与,而且需要转换成xaml。
以上就是wpf实现炫酷loading控件的全部内容,希望对大家的学习有所帮助。
dy("nrwz");
查看更多关于超炫酷的WPF实现Loading控件效果的详细内容...