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

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

3、如果报错找不到loading类型,请编译,下面在generic.xaml主题文件中对loading的样式和内容进行定义(注意添加
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 |
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和逻辑进行编码:
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
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控件的全部内容,希望对大家的学习有所帮助。








发表评论
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。