Question

I have two brushes. I don't know wath type of brushes they are. They can be ImageBrushes, SolidBrushes or 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.

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.
        }
    }
}

No correct solution

OTHER TIPS

The reason I need to animate a brush is to animate the brush in a material that I am using in a 3d object. 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.

Here is the MaterialAnimation Class for who needs it. I also have a Point3DCollectionAnimation Class. It can be used to animate 3D meshes. 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

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. However, I noticed that StackOverflow operates under the Creative Commons licence. 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>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top