tags:

views:

370

answers:

3

Is there a way to create a kind of "solidcolorbrush" that is a mixture of 2 solidcolor brushes?

For the back color, i would like to be able to use a DynamicReference to some other brush. While the other color (in the front) could be a static color with opacity.

Feel free to ask for clarification if this doesnt really make sence!

A: 

A SolidColorBrush will always be exactly one color.

So do you mean you want to mix these colors, like you mix yellow and red to get orange?

Arjan Einbu
exactly! The outcome of this mixture though should be 1 brush (of some kind)
Entrodus
+2  A: 

Get the colors from the foreground and background brushes, mix them, and create a new brush from the resulting color.

Example in C#:

Color foreground = foregroundBrush.Color;
Color background = backgroundBrush.Color;

int opacity = 25;

int r = (opacity * (foreground.R - background.R) / 100) + background.R;
int g = (opacity * (foreground.G - background.G) / 100) + background.G;
int b = (opacity * (foreground.B - background.B) / 100) + background.B;

SolidColorBrush mixedBrush = new SolidColorBrush(Color.FromArgb(r, g, b));
Guffa
Good example... but i was hoping for XAML version of this...
Entrodus
+1  A: 

Unfortunately, custom brushes are not supported in WPF (the brush types are marked 'internal' and cannot be inherited from), so creating a brush that is a mixture of two brushes that can be used from XAML like a normal SolidColorBrush is not possible.

As a workaround, you could use a MarkupExtension to simulate the behaviour of a custom brush, which allows you to use XAML syntax and provide a custom value, which allows us to use the built-in SolidColorBrush (no custom brush necessary) set to the value you get when mixing two colors:

/// <summary>
/// Markup extension to mix two SolidColorBrushes together to produce a new SolidColorBrush.
/// </summary>
[MarkupExtensionReturnType(typeof(SolidColorBrush))]
public class MixedColorBrush : MarkupExtension, INotifyPropertyChanged
{
    /// <summary>
    /// The foreground mix color; defaults to white.  
    /// If not changed, the result will always be white.
    /// </summary>
    private SolidColorBrush foreground = Brushes.White;

    /// <summary>
    /// The background mix color; defaults to black.  
    /// If not set, the result will be the foreground color.
    /// </summary>
    private SolidColorBrush background = Brushes.Black;

    /// <summary>
    /// PropertyChanged event for WPF binding.
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;

    /// <summary>
    /// Gets or sets the foreground mix color.
    /// </summary>
    public SolidColorBrush Foreground
    {
        get 
        { 
            return this.foreground; 
        }
        set 
        { 
            this.foreground = value; 
            this.NotifyPropertyChanged("Foreground"); 
        }
    }

    /// <summary>
    /// Gets or sets the background mix color.
    /// </summary>
    public SolidColorBrush Background
    {
        get 
        { 
            return this.background; 
        }
        set 
        { 
            this.background = value; 
            this.NotifyPropertyChanged("Background"); 
        }
    }

    /// <summary>
    /// Returns a SolidColorBrush that is set as the value of the 
    /// target property for this markup extension.
    /// </summary>
    /// <param name="serviceProvider">Object that can provide services for the markup extension.</param>
    /// <returns>The object value to set on the property where the extension is applied.</returns>
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        if (this.foreground != null && this.background != null)
        {
            // Create a new brush as a composite of the old ones
            // This does simple non-perceptual additive color, e.g 
            // blue + red = magenta, but you can swap in a different
            // algorithm to do subtractive color (red + yellow = orange)
            return new SolidColorBrush(this.foreground.Color + this.background.Color);
        }

        // If either of the brushes was set to null, return an empty (white) brush.
        return new SolidColorBrush();
    }

    /// <summary>
    /// Raise the property changed event.
    /// </summary>
    /// <param name="propertyName">Name of the property which has changed.</param>
    protected void NotifyPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Which can then be used from XAML as you would a normal brush:

<Grid>
    <Grid.Background>
        <local:MixedColorBrush Foreground="Blue" Background="Red"/>
    </Grid.Background>
</Grid>

Or by using the markup extension syntax:

<Grid Background="{local:MixedColorBrush Foreground=Blue, Background=Red}">

The downside to this approach is that you cannot use DynamicResource or StaticResource references to bind the values to other resources in your application. MarkupExtension is not a DependencyObject, and resource binding only works on DependencyObjects; the built-in Brushes are DependencyObjects, which is why binding works with traditional brushes.

Nicholas Armstrong