2

是否可以在 CodeBehind 中定义(而不是切换)VisualStates?

我正在创建一个装饰器,它在OnRender. 我想做的是通过它的属性来改变这些矩形的不透明度IsMouseOver(比如从 0.3 到 0.8)。

在任何带有可视化树的控件中,我都会添加一些 VisualStates 并使用 DataStateBehavior 切换它们。我如何用装饰器做到这一点?

4

3 回答 3

4

这是完全可能的。

如果有人对此感兴趣,我是如何做到的:

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>FrameworkElementSetBindingBindingOperations

  • 对于属性更改时的自动重新渲染,请记住设置FrameworkPropertyMetadataOptions.AffectsRender

于 2011-04-03T21:07:55.057 回答
0

如果您可以在代码中添加状态,则诸如 Blend 之类的工具必须以所有可能的配置运行所有代码,以找出存在/可能的状态。

所以,不,你不能在代码中做到这一点。只能使用属性。

编辑

我的立场得到纠正,但提到的问题仍然存在。这种技术对设计师没有用。

于 2011-04-03T16:15:30.817 回答
0

由于您已经使用自己的行为创建自定义装饰器,我建议您覆盖装饰器的 MouseOver 方法并更改那里的矩形的不透明度...

另一种方法是监听您自己的 PropertyChanged 事件并监视 IsMouseOver 中的更改,或者可能监视 MouseMove 事件...

于 2011-04-03T16:45:49.350 回答