是否可以在 CodeBehind 中定义(而不是切换)VisualStates?
我正在创建一个装饰器,它在OnRender
. 我想做的是通过它的属性来改变这些矩形的不透明度IsMouseOver
(比如从 0.3 到 0.8)。
在任何带有可视化树的控件中,我都会添加一些 VisualStates 并使用 DataStateBehavior 切换它们。我如何用装饰器做到这一点?
是否可以在 CodeBehind 中定义(而不是切换)VisualStates?
我正在创建一个装饰器,它在OnRender
. 我想做的是通过它的属性来改变这些矩形的不透明度IsMouseOver
(比如从 0.3 到 0.8)。
在任何带有可视化树的控件中,我都会添加一些 VisualStates 并使用 DataStateBehavior 切换它们。我如何用装饰器做到这一点?
这是完全可能的。
如果有人对此感兴趣,我是如何做到的:
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);
}));
}
实际上很简单。
这里的关键点是:
您不能设置 VisualStateGroups 附加属性。你必须得到集合,然后添加你自己的组
你不能这样做new DataStateBehavior{Binding = new Binding(...){...}}
,因为这不会为属性分配一些值。As不是从您那里派生的,也不能使用但必须使用该类。Behvior<T>
FrameworkElement
SetBinding
BindingOperations
对于属性更改时的自动重新渲染,请记住设置FrameworkPropertyMetadataOptions.AffectsRender
。
如果您可以在代码中添加状态,则诸如 Blend 之类的工具必须以所有可能的配置运行所有代码,以找出存在/可能的状态。
所以,不,你不能在代码中做到这一点。只能使用属性。
编辑
我的立场得到纠正,但提到的问题仍然存在。这种技术对设计师没有用。
由于您已经使用自己的行为创建自定义装饰器,我建议您覆盖装饰器的 MouseOver 方法并更改那里的矩形的不透明度...
另一种方法是监听您自己的 PropertyChanged 事件并监视 IsMouseOver 中的更改,或者可能监视 MouseMove 事件...