is it possible to define (not switch) VisualStates in CodeBehind?
I'm creating an Adorner, that draws some rectangles in OnRender
. What I'd like to do is to change the Opacity of these Rectangles by it's Property IsMouseOver
(say from 0.3 to 0.8).
In any control with a visual tree I'd add some VisualStates and switch those with a DataStateBehavior. How do I do this with an Adorner?
this is entirely possible.
if anyone is interested here is how I did it:
public class MyAdorner: Adorner
{
ctor (...):base(...)
{
...
var storyboard = new Storyboard();
var doubleAnimation = new DoubleAnimation(0.2,new Duration(TimeSpan.Zero));
Storyboard.SetTarget(doubleAnimation,this);
Storyboard.SetTargetProperty(doubleAnimation,new PropertyPath(RectOpacityProperty));
storyboard.Children.Add(doubleAnimation);
var storyboard2 = new Storyboard();
var doubleAnimation2 = new DoubleAnimation(0.5, new Duration(TimeSpan.Zero));
Storyboard.SetTarget(doubleAnimation2, this);
Storyboard.SetTargetProperty(doubleAnimation2, new PropertyPath(RectOpacityProperty));
storyboard2.Children.Add(doubleAnimation2);
var stateGroup = new VisualStateGroup { Name = "MouseOverState" };
stateGroup.States.Add(new VisualState { Name = "MouseOut", Storyboard = storyboard });
stateGroup.States.Add(new VisualState { Name = "MouseOver", Storyboard = storyboard2});
var sgs = VisualStateManager.GetVisualStateGroups(this);
sgs.Add(stateGroup);
var dsb = new DataStateBehavior
{
Value = true,
FalseState = "MouseOut",
TrueState = "MouseOver"
};
BindingOperations.SetBinding(dsb, DataStateBehavior.BindingProperty, new Binding {Source = this, Path = new PropertyPath(IsMouseOverProperty)});
dsb.Attach(this);
}
protected override void OnRender(DrawingContext drawingContext)
{
drawingContext.DrawRectangle(_mouseOverBrush, _pen, _rects[i]); //mouseoverbrush is a Solidcolorbrush
}
public double RectOpacity
{
get { return (double)GetValue(RectOpacityProperty); }
set { SetValue(RectOpacityProperty, value); }
}
public static readonly DependencyProperty RectOpacityProperty =
DependencyProperty.Register("RectOpacity", typeof(double), typeof(XmlNodeWrapperAdorner), new FrameworkPropertyMetadata(0.0,FrameworkPropertyMetadataOptions.AffectsRender,(o, args) =>
{
var adorner = o as MyAdorner;
adorner._mouseOverBrush.Color = Color.FromArgb((byte)((double)args.NewValue * 0xFF), 0xFF, 0xBE, 0x00);
}));
}
pretty straightforward actually.
key points here are:
you cannot set the VisualStateGroups attached property. you have to get the collection and then add your own group
you cannot do new DataStateBehavior{Binding = new Binding(...){...}}
as this will assign not bind some value to the property. As Behvior<T>
doesn't derive from FrameworkElement
you also can't use SetBinding
but have to use the BindingOperations
class.
for automatic rerendering when the property changes keep in mind to set FrameworkPropertyMetadataOptions.AffectsRender
.