WPF Animation based on property value -
i have dependency property double text, , want accomplish rotate (with animation) line text degrees whenever change value of text property.
is there better way implement ontextpropertychanged , there process animation? or done rather in xaml?
here demonstrating code:
mainwindow.xaml
<window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:l="clr-namespace:wpfapplication1" x:class="wpfapplication1.mainwindow" title="mainwindow" height="200" width="200" x:name="root"> <grid> <textbox width="50" height="20" verticalalignment="top" text="{binding text, elementname=root, mode=twoway}"/> <grid width="100" height="100" background="gray" x:name="grid"> <line grid.row="1" x2="100" y2="100" stroke="red"/> </grid> </grid> </window>
and mainwindow.xaml.cs (without usings):
namespace wpfapplication1 { public partial class mainwindow : window { public static readonly dependencyproperty textproperty = dependencyproperty.register( "text", typeof(double), typeof(mainwindow), new frameworkpropertymetadata(0.0)); public double text { { return (double)getvalue(textproperty); } set { setvalue(textproperty, value); } } public mainwindow() { initializecomponent(); } } }
this possible through binding so:
<textbox width="50" height="20" verticalalignment="top" text="{binding path=text, mode=twoway, updatesourcetrigger=propertychanged}"/> <grid width="100" height="100" background="gray" x:name="grid"> <line grid.row="1" x2="100" y2="100" stroke="red"> <line.rendertransform> <rotatetransform centerx="50" centery="50" angle="{binding path=text, mode=oneway, converter={staticresource resourcekey=stod}}"/> </line.rendertransform> </line> </grid>
your converter has convert string double return system.convert(value.tostring());
.
a cool feature discovered while testing this, validation rule automatically added returns validationerror if dont type double value textbox.
to make work have the mainwindows datacontext this.datacontext = this;
.
edit: wrote little helper class, animation you:
public class doubleanimationmanager { private static dictionary<dependencyobject, animationhelper> _helperdic = new dictionary<dependencyobject, animationhelper>(); public static propertypath getproperty(dependencyobject obj) { return (propertypath)obj.getvalue(propertyproperty); } public static void setproperty(dependencyobject obj, propertypath value) { obj.setvalue(propertyproperty, value); } public static readonly dependencyproperty propertyproperty = dependencyproperty.registerattached( "property", typeof(propertypath), typeof(doubleanimationmanager), new propertymetadata( (o, e) => { if (!_helperdic.containskey(o)) _helperdic[o] = new animationhelper(o); _helperdic[o].path = (propertypath)e.newvalue; })); public static int getdelaytimeinms(dependencyobject obj) { return (int)obj.getvalue(delaytimeinmsproperty); } public static void setdelaytimeinms(dependencyobject obj, int value) { obj.setvalue(delaytimeinmsproperty, value); } public static readonly dependencyproperty delaytimeinmsproperty = dependencyproperty.registerattached( "delaytimeinms", typeof(int), typeof(doubleanimationmanager), new propertymetadata(0, (o, e) => { if (!_helperdic.containskey(o)) _helperdic[o] = new animationhelper(o); _helperdic[o].delayinms = (int)e.newvalue; })); public static double getvalue(dependencyobject obj) { return (double)obj.getvalue(valueproperty); } public static void setvalue(dependencyobject obj, double value) { obj.setvalue(valueproperty, value); } public static readonly dependencyproperty valueproperty = dependencyproperty.registerattached( "value", typeof(double), typeof(doubleanimationmanager), new propertymetadata( (o, e) => { if (!_helperdic.containskey(o)) _helperdic[o] = new animationhelper(o); _helperdic[o].tovalue = (double)e.newvalue; if (!_helperdic[o].started) { _helperdic[o].fromvalue = (double)e.oldvalue; _helperdic[o].start(); } })); } public class animationhelper { private bool _remmode; private dependencyobject _target; private backgroundworker _bw = new backgroundworker(); public double fromvalue { get; set; } private double _tovalue; public double tovalue { { return _tovalue; } set { if (started) { _remmode = true; } _tovalue = value; } } public bool started { get; private set; } private int _delayinms; public int delayinms { { return _delayinms; } set { _delayinms = value; } } public propertypath path { get; set; } public animationhelper(dependencyobject target) { _target = target; _bw.dowork += delegate { system.threading.thread.sleep(delayinms); }; _bw.runworkercompleted += delegate { startanimation(); }; } private storyboard getstoryboard() { storyboard sb = new storyboard(); doubleanimation da = new doubleanimation(tovalue, new timespan(0, 0, 3)); da.from = fromvalue; storyboard.settarget(da, _target); storyboard.settargetproperty(da, path); sb.children.add(da); sb.completed += delegate { if (_remmode) { startanimation(); _remmode = false; } else { started = false; } }; return sb; } private void startanimation() { getstoryboard().begin(); fromvalue = tovalue; } public void start() { started = true; _bw.runworkerasync(); } }
how use it:
<textbox width="50" height="20" verticalalignment="top" text="{binding path=text, mode=twoway, updatesourcetrigger=propertychanged}"/> <grid width="100" height="100" background="gray" x:name="grid"> <line grid.row="1" x2="100" y2="100" stroke="red" local:doubleanimationmanager.property="(uielement.rendertransform).(rotatetransform.angle)" local:doubleanimationmanager.value="{binding path=text, mode=oneway, converter={staticresource resourcekey=stod}}"> <line.rendertransform> <rotatetransform centerx="50" centery="50"/> </line.rendertransform> </line> </grid>
Comments
Post a Comment