从代码隐藏定义 VisualStates

发布于 2024-10-30 09:58:58 字数 246 浏览 1 评论 0原文

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

我正在创建一个装饰器,它在 OnRender 中绘制一些矩形。我想做的是通过其属性 IsMouseOver 更改这些矩形的不透明度(例如从 0.3 到 0.8)。

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

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

岁月静好 2024-11-06 09:58:58

这是完全有可能的。

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

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(...){...}},因为这将分配 不将某些值绑定到该属性。由于 Behvior 不是从 FrameworkElement 派生的,因此您也不能使用 SetBinding 但必须使用 BindingOperations code> class。

  • 为了在属性更改时自动重新渲染,请记住设置FrameworkPropertyMetadataOptions.AffectsRender

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.

蔚蓝源自深海 2024-11-06 09:58:58

由于您已经使用自己的行为创建了自定义装饰器,因此我建议您重写装饰器的 MouseOver 方法并更改其中矩形的不透明度...

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

Since you're already creating a custom adorner with your own behavior, i would suggest that you override the MouseOver method of the adorner and change the opacity of your rectangles there...

another way would be to listen to your own PropertyChanged event and monitor the change in IsMouseOver, or maybe monitor the MouseMove event...

策马西风 2024-11-06 09:58:58

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

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

编辑

我已经纠正,但提到的问题仍然存在。这种技术对于设计师来说没有用。

If you could add States in code, tools such as Blend would have to run all code in all possible configurations to find out what states are present/possible.

So, no, you can't do this in code. It only possible using attributes.

EDIT

I stand corrected but the problem mentioned still remains. This technique is not useful for designers.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文