views:

129

answers:

3

I am making a bar chart and I want two separate gradients for each bar. First I want a gradient to go from top to bottom solid red to transparent red. I want to paint over the top of that a gradient that goes from right to left, black to opaque.

So - In the bottom left we should have;

  • Bottom left - Alpha 0
  • Bottom right - Alpha 0
  • Top left - Alpha 255 Colour Red
  • Top Right - Alpha 255 Colour Black

So in effect I want to take a solid colour, add a left to right gradient to black then take the output of that and add a top to bottom gradient to transparency.

All this and I want it to be in a single brush, is this even possible?

A: 

If the template for your bar is based on Grids, you could then overlay the 2 gradients as below. I am not sure I fully understood what you wanted for your 2nd gradient, but I assume you mean left-to-right, transparent black to solid black. If I misunderstood, it is easy to change the 2nd gradient in the XAML below.

<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&gt;
    <Grid Width="100" Height="300" >
        <Grid>
            <Grid.Background>
                <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                    <GradientStop Color="#FFFF0000" Offset="0" />
                    <GradientStop Color="#00FF0000" Offset="1" />
                </LinearGradientBrush>
            </Grid.Background>
        </Grid>
        <Grid>
            <Grid.Background>
                <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
                    <GradientStop Color="#00000000" Offset="0" />
                    <GradientStop Color="#FF000000" Offset="1" />
                </LinearGradientBrush>
            </Grid.Background>
        </Grid>
    </Grid>
</UserControl>

Paste this XAML into Charles Petzold's XAML Cruncher to see the results.

Good luck,
Jim McCurdy
Face to Face Software and YinYangMoney

Jim McCurdy
A: 

"In a single brush" I'd say "not in the brushes provided" - but you can always create your own...

Dan Puzey
+3  A: 

Yes. Use a VisualBrush whose Visual is a Rectangle inside a Border to combine the other two brushes.

Something like this:

<LinearGradientBrush x:Key="UnderBrush" EndPoint="0,1"> 
  <GradientStop Color="#FFFF0000" Offset="0" /> 
  <GradientStop Color="#00FF0000" Offset="1" /> 
</LinearGradientBrush> 

<LinearGradientBrush x:Key="OverBrush" EndPoint="1,0"> 
  <GradientStop Color="#00000000" Offset="0" /> 
  <GradientStop Color="#FF000000" Offset="1" /> 
</LinearGradientBrush> 

<VisualBrush x:Key="CombinedBrush">
  <VisualBrush.Visual>
    <Border Background="{StaticResource UnderBrush}">
      <Rectangle Fill="{StaticResource OverBrush}" Width="1" Height="1" />
    </Border>
  </VisualBrush.Visual>
</VisualBrush>

CombinedBrush can be used to paint your bars, and you will get the effect you describe.

Silverlight version

Since Silverlight has no VisualBrush you must build a WritableBitmap in code and use it with an ImageBrush:

<ImageBrush x:Key="CombinedBrush">
  <my:VisualBrushSimulator.Visual>
    <Border Background="{StaticResource UnderBrush}">
      <Rectangle Fill="{StaticResource OverBrush}" Width="1" Height="1" />
    </Border>
  </my:VisualBrushSimulator.Visual>
</ImageBrush>

Here is how the VisualBrushSimulator might be implemented:

public class VisualBrushSimulator : DependencyObject
{
  public Visual GetVisual(DependencyObject obj) { return (Visual)obj.GetValue(VisualProperty); }
  public void SetVisual(DependencyObject obj, Visual value) { obj.SetValue(VisualProperty, value); }
  public static readonly DependencyProperty VisualProperty = DependencyProperty.RegisterAttached("Visual", typeof(Visual), typeof(VisualBrushSimulator), new PropertyMetadata
  {
    PropertyChangedCallback = (obj, e) =>
    {
      int width=1000;
      int height=1000;
      var bitmap = new WritableBitmap(width, height);
      bitmap.Render((Visual)e.NewValue, new ScaleTransform { ScaleX = width, ScaleY = height });
      ((ImageBrush)obj).ImageSource = bitmap;
    }
  });
}

Note that this is not a true VisualBrush simulation, since changes to the Visual do not affect the brush.

Ray Burns
There is no VisualBrush in Silverlight
Jim McCurdy
The question was tagged both WPF and Silverlight. Without VisualBrush this is more difficult and requires some code-behind but can still be accomplished. I'll update my answer for Silverlight support.
Ray Burns