简体   繁体   English

如何在WPF中组合画笔?

[英]How do I combine brushes in WPF?

I have two brushes. 我有两个刷子。 I don't know wath type of brushes they are. 我不知道它们是哪种刷子。 They can be ImageBrushes, SolidBrushes or VisualBrushes. 它们可以是ImageBrushes,SolidBrushes或VisualBrushes。 I have each in a variable of the "Brush" type. 我每个都有一个“画笔”类型的变量。

I need to combine two brushes. 我需要结合两个画笔。 How do I do it? 我该怎么做?

I tried this. 我试过了 But It didn't work. 但这没有用。 Here are Back and Front the brushes that need to me combined. 这是需要我组合的“后”和“前”刷子。

Border Bd = new Border();
Border Bdr = new Border();

Bd.Width = 1.0;
Bd.Height = 1.0;

Bd.Background = Back;
Bdr.Background = Front;

Bd.Child = Bdr;

Brush VB = new VisualBrush(Bd);

I need this because I am making a custom animation class to animate brushes. 我需要这个,因为我正在制作一个自定义动画类来为笔刷制作动画。 After making some test's I concluded that the error is in the combining of the brushes and not elsewhere in the class. 经过一些测试后,我得出结论,错误在于画笔的组合,而不是课堂上的其他地方。

The resulting brush is completely transparent. 生成的画笔是完全透明的。


[EDIT] [编辑]

Here is the complete BrushAnimation Class. 这是完整的BrushAnimation类。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media.Animation;
using System.Windows;
using System.Windows.Media;
using System.Windows.Controls;

namespace WPFSoPaTest
{
    class BrushAnimation : AnimationTimeline
    {
                protected override Freezable CreateInstanceCore()
        {
            return new BrushAnimation();
        }
        public override Type TargetPropertyType
        {
            get { return typeof(Brush); }
        }
        static BrushAnimation()
        {
            FromProperty = DependencyProperty.Register("From", typeof(Brush),
                typeof(BrushAnimation));

            ToProperty = DependencyProperty.Register("To", typeof(Brush),
                typeof(BrushAnimation));
        }
        public static readonly DependencyProperty FromProperty;
        public Brush From
        {
            get
            {
                return (Brush)GetValue(BrushAnimation.FromProperty);
            }
            set
            {
                SetValue(BrushAnimation.FromProperty, value);
            }
        }
        public static readonly DependencyProperty ToProperty;
        public Brush To
        {
            get
            {
                return (Brush)GetValue(BrushAnimation.ToProperty);
            }
            set
            {
                SetValue(BrushAnimation.ToProperty, value);
            }
        }
        public override object GetCurrentValue(object defaultOriginValue,
        object defaultDestinationValue, AnimationClock animationClock)
        {
            Brush fromVal = ((Brush)GetValue(BrushAnimation.FromProperty)).CloneCurrentValue();
            Brush toVal = ((Brush)GetValue(BrushAnimation.ToProperty)).CloneCurrentValue();

            if ((double)animationClock.CurrentProgress == 0.0)
                return fromVal; //Here it workes fine.

            if ((double)animationClock.CurrentProgress == 1.0)
                return toVal;   //It workes also here fine.

            toVal.Opacity = (double)animationClock.CurrentProgress;


            Border Bd = new Border();
            Border Bdr = new Border();

            Bd.Width = 1.0;
            Bd.Height = 1.0;

            Bd.Background = fromVal;
            Bdr.Background = toVal;

            Bd.Visibility = Visibility.Visible;
            Bdr.Visibility = Visibility.Visible;
            Bd.Child = Bdr;

            Brush VB = new VisualBrush(Bd);
            return VB; //But here it return's a transparent brush.

            //If I return the 'toVal' variable here it animates correctly the opacity.
        }
    }
}

The reason I need to animate a brush is to animate the brush in a material that I am using in a 3d object. 我需要为笔刷设置动画的原因是要在3D对象中使用的材质中为笔刷设置动画。 I thought it would be easier to animate the brush than the material. 我认为,为画笔设置动画比材质更容易。

I have already used the method above to combinate brushes, but it didn't work here. 我已经使用了上面的方法来组合画笔,但是在这里不起作用。

After thinking a little bit I decided to animate the Material and not the brush. 经过一番思考后,我决定为材质而不是画笔设置动画。 It resulted to be easier than animating a brush. 结果比动画画笔更容易。

[NOTE] [注意]
This animation class is adapted for my needs. 这个动画课适合我的需要。 It only animates the brush in the material. 它仅使画笔在材质中动起来。 I am using this class to replace the brush of a material for an other. 我正在使用此类替换其他材料的画笔。

[NOTE] [注意]
The 'to material' will at the end replace completely the 'from material', it will not end with a MaterialGroup. 最后,“到材料”将完全替换“从材料”,而不会以MaterialGroup结尾。

Here is the MaterialAnimation Class for who needs it. 这是谁需要它的MaterialAnimation类。 I also have a Point3DCollectionAnimation Class. 我也有一个Point3DCollectionAnimation类。 It can be used to animate 3D meshes. 它可用于为3D网格设置动画。 It's very useful. 非常有用 You can find it below this one. 您可以在此下面找到它。

MaterialAnimation 材质动画

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media.Animation;
using System.Windows;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows.Media.Media3D;

namespace System.Windows.Media.Animation
{
    class MaterialAnimation : AnimationTimeline
    {
                protected override Freezable CreateInstanceCore()
        {
            return new MaterialAnimation();

        }
        public override Type TargetPropertyType
        {
            get { return typeof(Material); }
        }
        static MaterialAnimation()
        {
            FromProperty = DependencyProperty.Register("From", typeof(Material),
                typeof(MaterialAnimation));

            ToProperty = DependencyProperty.Register("To", typeof(Material),
                typeof(MaterialAnimation));
        }
        public static readonly DependencyProperty FromProperty;
        public Material From
        {
            get
            {
                return (Material)GetValue(MaterialAnimation.FromProperty);
            }
            set
            {
                SetValue(MaterialAnimation.FromProperty, value);
            }
        }
        public static readonly DependencyProperty ToProperty;
        public Material To
        {
            get
            {
                return (Material)GetValue(MaterialAnimation.ToProperty);
            }
            set
            {
                SetValue(MaterialAnimation.ToProperty, value);
            }
        }
        public override object GetCurrentValue(object defaultOriginValue,
        object defaultDestinationValue, AnimationClock animationClock)
        {
            Material fromVal = ((Material)GetValue(MaterialAnimation.FromProperty)).CloneCurrentValue();
            Material toVal = ((Material)GetValue(MaterialAnimation.ToProperty)).CloneCurrentValue();

            if ((double)animationClock.CurrentProgress == 0.0)
                return fromVal; //Here it workes fine.

            if ((double)animationClock.CurrentProgress == 1.0)
                return toVal;   //It workes also here fine.            

            if (toVal.GetType() == (new DiffuseMaterial()).GetType())
                ((DiffuseMaterial)toVal).Brush.Opacity = (double)animationClock.CurrentProgress;
            else
                if (toVal.GetType() == (new SpecularMaterial()).GetType())
                    ((SpecularMaterial)toVal).Brush.Opacity = (double)animationClock.CurrentProgress;
                else
                    ((EmissiveMaterial)toVal).Brush.Opacity = (double)animationClock.CurrentProgress;


            MaterialGroup MG = new MaterialGroup();

            MG.Children.Add(fromVal);
            MG.Children.Add(toVal);            

            return MG; 
        }
    }
}


Here is the Point3DCollectionAnimation Class. 这是Point3DCollectionAnimation类。

Point3DCollectionAnimation Point3DCollectionAnimation

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media.Animation;
using System.Windows;
using System.Windows.Media.Media3D;

namespace System.Windows.Media.Animation
{
    public class Point3DCollectionAnimation : AnimationTimeline
    {
        protected override Freezable CreateInstanceCore()
        {
            return new Point3DCollectionAnimation();
        }
        public override Type TargetPropertyType
        {
            get { return typeof(Point3DCollection); }
        }
        static Point3DCollectionAnimation()
        {
            FromProperty = DependencyProperty.Register("From", typeof(Point3DCollection),
                typeof(Point3DCollectionAnimation));

            ToProperty = DependencyProperty.Register("To", typeof(Point3DCollection),
                typeof(Point3DCollectionAnimation));
        }
        public static readonly DependencyProperty FromProperty;
        public Point3DCollection From
        {
            get
            {
                return (Point3DCollection)GetValue(Point3DCollectionAnimation.FromProperty);
            }
            set
            {
                SetValue(Point3DCollectionAnimation.FromProperty, value);
            }
        }
        public static readonly DependencyProperty ToProperty;
        public Point3DCollection To
        {
            get
            {
                return (Point3DCollection)GetValue(Point3DCollectionAnimation.ToProperty);
            }
            set
            {
                SetValue(Point3DCollectionAnimation.ToProperty, value);
            }
        }
        public override object GetCurrentValue(object defaultOriginValue,
        object defaultDestinationValue, AnimationClock animationClock)
        {
            Point3DCollection fromVal = ((Point3DCollection)GetValue(Point3DCollectionAnimation.FromProperty));
            Point3DCollection toVal = ((Point3DCollection)GetValue(Point3DCollectionAnimation.ToProperty));

            Point3DCollection ret;

            int t = 0;
            if (fromVal.Count > toVal.Count)
            {
                ret = fromVal.Clone();
                foreach (Point3D tov in toVal)
                {
                    Point3D frov = fromVal[t];
                    Point3D newv = new Point3D();

                    newv.X = (double)animationClock.CurrentProgress * (tov.X - frov.X) + frov.X;
                    newv.Y = (double)animationClock.CurrentProgress * (tov.Y - frov.Y) + frov.Y;
                    newv.Z = (double)animationClock.CurrentProgress * (tov.Z - frov.Z) + frov.Z;
                    ret[t] = newv;
                    t++;
                }
            }
            else
            {
                ret = toVal.Clone();
                foreach (Point3D frov in fromVal)
                {
                    Point3D tov = toVal[t];
                    Point3D newv = new Point3D();

                    newv.X = (double)animationClock.CurrentProgress * (tov.X - frov.X) + frov.X;
                    newv.Y = (double)animationClock.CurrentProgress * (tov.Y - frov.Y) + frov.Y;
                    newv.Z = (double)animationClock.CurrentProgress * (tov.Z - frov.Z) + frov.Z;
                    ret[t] = newv;
                    t++;
                }
            }

            return ret;
        }
    }
}

I hope these classes are usefull for who needs them. 我希望这些课程对谁需要它们有用。 I searched for them allot on the internet, but didn't find them. 我在互联网上搜索了它们的分配,但没有找到它们。 I'm sure that there are more people who needs these classes. 我敢肯定会有更多需要这些课程的人。

Please leave comments. 请发表评论。

I discovered the problem. 我发现了问题。 Visual Brushes are not freezable. 视觉笔刷不可冻结。 To the code to work I will need to find a way to freeze the brush. 为了使代码正常工作,我需要找到冻结笔刷的方法。

Aaron, I have used your BrushAnimation class as shown above, and it works for my specific needs. 亚伦,我使用了如上所示的BrushAnimation类,它可以满足我的特定需求。 However, I noticed that StackOverflow operates under the Creative Commons licence. 但是,我注意到StackOverflow在知识共享许可下运行。 Thus I technically couldn't use that class in my commercial application (which I don't want to be under the Creative Commons licence) without your permission. 因此,未经您的许可,从技术上讲,我不能在我的商业应用程序中使用该类(我不希望获得知识共享许可)。 Are you willing to give me permission? 你愿意给我许可吗? I can still credit your work. 我仍然可以相信你的工作。

I couldn't find any other way to contact you about this, since I can't make comments yet. 由于无法发表评论,因此我无法找到其他任何方式与您联系。

The above approach should work as long as you have transparent pixels in the front brush. 只要前面的画笔中有透明像素,上述方法就应该起作用。 If not the front brush would just overlay the back brush. 如果不是,则前刷将仅覆盖后刷。 You should provide a more complete example to see what is actually going on. 您应该提供一个更完整的示例,以了解实际情况。

You can use a visualbrush to achieve that 您可以使用视觉刷来实现

<Grid.Background>
       <VisualBrush>
                <VisualBrush.Visual>
                    <Grid 
                        Width="{Binding Path=ActualWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type FrameworkElement}}, Mode=OneWay}" 
                        Height="{Binding Path=ActualHeight, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type FrameworkElement}}, Mode=OneWay}">

                        <Rectangle Fill="Blue" />
                        <Image Source="your image path" Stretch="Uniform" />

                    </Grid>
                </VisualBrush.Visual>
            </VisualBrush>
        </Grid.Background>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM