How to get DrawingImage out of the Style? - wpf

I had the DrawingBrush placed as below -
<DrawingBrush Viewbox="0,0,39.125,39.125" ViewboxUnits="Absolute">
<DrawingBrush.Drawing>
<GeometryDrawing Brush="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=uiEntityViews:NodeCanvasView}, Path=MyColor}" Geometry="F1M19.5625,0.999954C29.8144,0.999954 38.125,9.31053 38.125,19.5625 38.125,29.8142 29.8143,38.1249 19.5625,38.1249 9.31073,38.1249 1,29.8142 1,19.5625 1,9.31053 9.31064,0.999954 19.5625,0.999954z">
<GeometryDrawing.Pen>
<Pen DashCap="Square" EndLineCap="Flat" LineJoin="Round" MiterLimit="10" StartLineCap="Flat" Thickness="2">
<Pen.Brush>
<LinearGradientBrush EndPoint="0.849422,0.849423" StartPoint="0.150577,0.150578">
<GradientStop Color="#FF657783" Offset="0"/>
<GradientStop Color="White" Offset="0.146"/>
<GradientStop Color="#FF2C4758" Offset="1"/>
</LinearGradientBrush>
</Pen.Brush>
<Pen.DashStyle>
<DashStyle/>
</Pen.DashStyle>
</Pen>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
With this, I can get image from DrawingBursh as follows -
if (resourceObject is DrawingBrush)
{
DrawingBrush iconBrush = resourceObject as DrawingBrush;
DrawingImage image = new DrawingImage(iconBrush.Drawing);
resourceObject = image;
}
Now, I added the DrawingBrush within the style like below -
<Style x:Key="MY_ICON_STYLE" TargetType="Rectangle">
<Setter Property="Fill">
<Setter.Value>
<DrawingBrush Viewbox="0,0,39.125,39.125" ViewboxUnits="Absolute">
<DrawingBrush.Drawing>
<GeometryDrawing Brush="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=uiEntityViews:NodeCanvasView}, Path=MyColor}" Geometry="F1M19.5625,0.999954C29.8144,0.999954 38.125,9.31053 38.125,19.5625 38.125,29.8142 29.8143,38.1249 19.5625,38.1249 9.31073,38.1249 1,29.8142 1,19.5625 1,9.31053 9.31064,0.999954 19.5625,0.999954z">
<GeometryDrawing.Pen>
<Pen DashCap="Square" EndLineCap="Flat" LineJoin="Round" MiterLimit="10" StartLineCap="Flat" Thickness="2">
<Pen.Brush>
<LinearGradientBrush EndPoint="0.849422,0.849423" StartPoint="0.150577,0.150578">
<GradientStop Color="#FF657783" Offset="0"/>
<GradientStop Color="White" Offset="0.146"/>
<GradientStop Color="#FF2C4758" Offset="1"/>
</LinearGradientBrush>
</Pen.Brush>
<Pen.DashStyle>
<DashStyle/>
</Pen.DashStyle>
</Pen>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
</Setter.Value>
</Setter>
</Style>
In this case, I am not sure how to get DrawingImage out of this Style like below -
if (resourceObject is Style)
{
Style iconStyle = resourceObject as Style;
//How to get drawingImage out of iconStyle
// DrawingImage image = new DrawingImage(iconStyle.DrawingBrush);
//resourceObject = iconStyle;
}

if (resourceObject is Style)
{
Style iconStyle = resourceObject as Style;
if (iconStyle != null)
{
foreach (var setter in iconStyle.Setters.OfType<Setter>())
{
if (setter.Value is DrawingBrush)
{
DrawingBrush iconBrush = (DrawingBrush)setter.Value;
DrawingImage image = new DrawingImage(iconBrush.Drawing);
resourceObject = image;
break;
}
}
}
}

Related

WPF Control OverrideMetadata: specify default value to come from resource

I would like to specify a resource as a default value for my control for the BorderBrushProperty. The reason being the brush is a LinearGradientBrush which I defined in XAML. So I'm looking for something like this in my static CTOR (3rd line):
static Gauge()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof (Gauge), new FrameworkPropertyMetadata(typeof (Gauge)));
BorderThicknessProperty.OverrideMetadata(typeof (Gauge), new FrameworkPropertyMetadata(new Thickness(16)));
BorderBrushProperty.OverrideMetadata(typeof (Gauge), new FrameworkPropertyMetadata("OuterFrameStroke"));
}
This is what my XAML looks like (in themes\generic.xaml):
<LinearGradientBrush x:Key="OuterFrameStroke" EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF636060" Offset="1" />
<GradientStop Color="#FF5F5C5C" Offset="0" />
<GradientStop Color="#FFEEDEDE" Offset="0.35" />
<GradientStop Color="#FFA09595" Offset="0.705" />
</LinearGradientBrush>
Well, should have thought 2 seconds longer. Of course I can set this default property in my template
<Style TargetType="gauge:Gauge">
<Setter Property="BorderBrush">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFA3AFD6" Offset="0.321" />
<GradientStop Color="#FF8399A9" Offset="0.674" />
<GradientStop Color="#FF718597" Offset="0.375" />
<GradientStop Color="#FF617584" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>

Create custom shape consisting of multiple single lines

i want to create a simple cross, that consists of two lines. The lines should have different colors. I've created a class that inherits form Shape. This class contains the two lines and computes the coordinates of the lines. I've read that i have to implement the DefiningGeometry property if i inherit from Shape. But how can i return both lines in the get section of that property?
Thanks in advance.
It sounds like you could use the CombinedGeometry Class to combine your lines together... the only thing is that you'll need to use LineGeometry classes instead of Lines. You could do something like this (from the linked CombinedGeometry page on MSDN):
<Path Stroke="Black" StrokeThickness="1" Fill="#CCCCFF">
<Path.Data>
<!-- Combines two geometries using the XOR combine mode. -->
<CombinedGeometry GeometryCombineMode="Xor">
<CombinedGeometry.Geometry1>
<EllipseGeometry RadiusX="50" RadiusY="50" Center="75,75" />
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
<EllipseGeometry RadiusX="50" RadiusY="50" Center="125,75" />
</CombinedGeometry.Geometry2>
</CombinedGeometry>
</Path.Data>
</Path>
Of course, you'd want to replace these EllipseGeometry objects with LineGeometry objects, but that shouldn't be difficult as they have similar properties.
UPDATE >>>
Unfortunately, I don't think that you can use a CombinedGeometry object that contains geometries of different colours... the whole shape would have to be painted with one Brush. However, you could fake two colours with cleverly positioned GradientStops. Also, as #Clemens mentioned, perhaps a GeometryGroup would be easier for you to use... try something like this:
<Path StrokeThickness="5" Fill="Blue" HorizontalAlignment="Center" VerticalAlignment="Center">
<Path.Data>
<GeometryGroup>
<LineGeometry StartPoint="50,0" EndPoint="50,100" />
<LineGeometry StartPoint="0,50" EndPoint="100,50" />
</GeometryGroup>
</Path.Data>
<Path.Stroke>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="LightGreen" Offset="0" />
<GradientStop Color="LightGreen" Offset="0.475" />
<GradientStop Color="Red" Offset="0.475" />
<GradientStop Color="Red" Offset="0.525" />
<GradientStop Color="LightGreen" Offset="0.525" />
<GradientStop Color="LightGreen" Offset="0" />
</LinearGradientBrush>
</Path.Stroke>
</Path>
This Brush will appear as if it were actually different colours on the two lines:
Then all you'll need to do is to convert this into C# to return it from the DefiningGeometry property. Please use the examples from the linked pages and the GeometryGroup class page on MSDN to help you with this.
You may draw two differently colored lines by means of two GeometryDrawings in a DrawingBrush that fills a Rectangle:
<Rectangle Width="20" Height="20">
<Rectangle.Fill>
<DrawingBrush>
<DrawingBrush.Drawing>
<DrawingGroup>
<GeometryDrawing Geometry="M0,-10 L0,10">
<GeometryDrawing.Pen>
<Pen Brush="Blue" Thickness="3"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
<GeometryDrawing Geometry="M-10,0 L10,0">
<GeometryDrawing.Pen>
<Pen Brush="Red" Thickness="3"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Rectangle.Fill>
</Rectangle>

How to create a shape with a gradient fill, and add it to a border background in WPF

I am trying to create the following shape as a background to a border. You will notice that the bottom section on the shape has a linear gradient to it.
I have played around with lines and shapes and gradients, but i have not been able to apply the below to a border. nor can i get a shape that looks like that.
Is this even possible? if so, can anyone help
The below XAML produces a brush that looks similar to your picture. You should play around the colors, offsets, and the rest for the best appearance.
<DrawingBrush x:Key="br1" Viewbox="0,0,100,100" ViewboxUnits="Absolute" >
<DrawingBrush.Drawing>
<DrawingGroup>
<GeometryDrawing Brush="Lavender">
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="0,0,100,100" />
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing>
<GeometryDrawing.Brush>
<RadialGradientBrush GradientOrigin="0.5,0.01" Center="0.5,-0.2" RadiusX="100">
<GradientStop Color="MidnightBlue" Offset="1.0" />
<GradientStop Color="LightSteelBlue" Offset="0.0" />
</RadialGradientBrush>
</GeometryDrawing.Brush>
<GeometryDrawing.Geometry>
<EllipseGeometry Center="60,310" RadiusX="160" RadiusY="300" />
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
Have fun!

Solid transparent line in WPF gradient

I am trying to draw a transparent line in a solid block using a gradient:
<Grid>
<Border Margin="-102,-27,102,27">
<Border.Background>
<LinearGradientBrush EndPoint="517,160" StartPoint="0,160" MappingMode="Absolute">
<GradientStop Color="#FF2DBCF2" Offset="0"/>
<GradientStop Color="#FF2DBCF2" Offset="1"/>
<GradientStop Color="#002DBCF2" Offset="0.0091" />
<GradientStop Color="#FF2DBCF2" Offset="0.009"/>
<GradientStop Color="#002DBCF2" Offset="0.015"/>
<GradientStop Color="#FF2DBCF2" Offset="0.0151"/>
</LinearGradientBrush>
</Border.Background>
</Border>
</Grid>
The problem is that on the edges of the gap in the solid colour block there is a faint fading effect which makes the edge slightly less than crisp. Is there a way to get rid of this faint fading? I just can't seem to find a way around it.
You may use something like the following DrawingBrush for the background:
<Border Margin="-102,-27,102,27">
<Border.Background>
<DrawingBrush>
<DrawingBrush.Drawing>
<GeometryDrawing Brush="#FF2DBCF2">
<GeometryDrawing.Geometry>
<GeometryGroup>
<RectangleGeometry Rect="0,0,0.01,1"/>
<RectangleGeometry Rect="0.015,0,0.985,1"/>
</GeometryGroup>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
</Border.Background>
</Border>
The only way to get a sharp line in the background is to use an ImageBrush or DrawingBrush as background instead of a LinearGradientBrush
I can't work out a complete example right now, but this should get you started on how to implement a DrawingBrush as background.
<Border.Background>
<DrawingBrush TileMode="Tile" Stretch="None" Viewport="0,0,20,20" ViewportUnits="Absolute">
<DrawingBrush.Drawing>
<GeometryDrawing>
<GeometryDrawing.Pen>
<Pen Brush="White"/>
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<LineGeometry StartPoint="0.3,0"
EndPoint="0.3,20"/>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
<Border.Background>

Transparent system color in gradient (WPF)

How to achieve such effect in XAML:
<LinearGradientBrush x:Key="BrightSeparatorGradient" StartPoint="0.0, 0.5" EndPoint="1.0, 0.5">
<GradientStop Offset="0.0" Color="{StaticResource {x:Static SystemColors.ControlLightColorKey}}" /> <!-- But fully transparent -->
<GradientStop Offset="0.5" Color="{StaticResource {x:Static SystemColors.ControlLightColorKey}}" />
<GradientStop Offset="1.0" Color="{StaticResource {x:Static SystemColors.ControlLightColorKey}}" /> <!-- But fully transparent -->
</LinearGradientBrush>
I've tried to create two brushes with appropriate color and Opacity set, respectively, to 0.0 and 1.0, but the compiler refused to take Brush as a Color (what is quite logic, on a second thought :)).
Best regards -- Spook.
I would create a MarkupExtension that takes a Color and returns the Color with the specified opacity:
public class OpacityExtension : MarkupExtension
{
private readonly Color color;
public byte Opacity { get; set; } // defaults to 0, so you don't have
// to set it for the color to be transparent
public OpacityExtension(Color color)
{
this.color = color;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return Color.FromArgb(Opacity, color.R, color.G, color.B);
}
}
And then you use it like so:
<LinearGradientBrush x:Key="BrightSeparatorGradient" StartPoint="0.0, 0.5" EndPoint="1.0, 0.5">
<GradientStop Offset="0" Color="{lcl:Opacity {StaticResource {x:Static SystemColors.ControlLightColorKey}}}" />
<GradientStop Offset=".5" Color="{StaticResource {x:Static SystemColors.ControlLightColorKey}}" />
<GradientStop Offset="1" Color="{lcl:Opacity {StaticResource {x:Static SystemColors.ControlLightColorKey}}}" />
</LinearGradientBrush>
Spook,
Why the following doesn't work for you?
<LinearGradientBrush x:Key="BrightSeparatorGradient" StartPoint="0.0, 0.5" EndPoint="1.0, 0.5">
<GradientStop Offset="0.0" Color="Transparent" />
<GradientStop Offset="0.5" Color="{StaticResource {x:Static SystemColors.ControlLightColorKey}}" />
<GradientStop Offset="1.0" Color="Transparent" />
</LinearGradientBrush>

Resources