Reputation: 2735
I'm using SharpVectors to embed svg file in my XAML.
Here is my Button
ControlTemplate
:
<ControlTemplate x:Key="ButtonTemplate" TargetType="Button">
<Border BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="True">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<svgc:SvgViewbox x:Name="svgIcon" Grid.Column="0" Margin="{TemplateBinding Padding}" Height="20" Width="20" Stretch="Uniform" />
<customUserControl:ExtendedBinding Grid.Column="0"
Source="{Binding ElementName=svgIcon,Path=Source,Mode=TwoWay}"
Target="{Binding Path=Tag, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}" />
<ContentPresenter x:Name="contentPresenter"
Grid.Column="1"
Focusable="False"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Grid>
</Border>
</ControlTemplate>
And here is an example of creating a button:
<Button Content="Text" Tag="../../../../Assets/Icons/cross.svg" Click="OnClick"/>
What I obtain is a SVG icon with a text inside my button.
Now I'd like to change the background color of my SVG on MouseOver
(exactly the same behaviour asked here, the difference is that I do not have a "Fill" tag in my svgc:SvgViewbox
.
Is there a way to solve my problem?
Update: My SVG file is a standard SVG, like this:
<g>
<g>
<path d="M311.517,14.053c-99.265,0-180.024,80.66-180.024,179.805c0,41.538,14.182,79.827,37.955,110.303L0,451.176l22.889,26.313 l170.577-147.994c31.628,27.496,72.926,44.168,118.051,44.168c99.266,0,180.025-80.661,180.025-179.805 C491.542,94.713,410.784,14.053,311.517,14.053z M311.517,353.663c-88.237,0-160.024-71.688-160.024-159.805 S223.279,34.053,311.517,34.053s160.025,71.688,160.025,159.805S399.755,353.663,311.517,353.663z" fill="#FFFFFF"/>
<polygon points="322.447,122.812 300.587,122.812 300.587,182.928 240.471,182.928 240.471,204.788 300.587,204.788 300.587,264.904 322.447,264.904 322.447,204.788 382.563,204.788 382.563,182.928 322.447,182.928 " fill="#000000"/>
</g>
</g>
Upvotes: 0
Views: 4325
Reputation: 5015
I found a solution to get it working via reflection.
Also opened an issue at the github (https://github.com/ElinamLLC/SharpVectors/issues/88) repo to make the properties public and easily access them.
SvgDrawingCanvas canvas = (SvgDrawingCanvas) fooSvgViewbox.Child;
List<Drawing> drawings = (List<Drawing>)typeof(SvgDrawingCanvas).GetField("_drawObjects", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(canvas);
foreach (Drawing drawing in drawings)
{
if (drawing is GeometryDrawing geometryDrawing)
{
geometryDrawing.Brush = Brushes.BlueViolet;
}
}
If you look at the class code (https://github.com/ElinamLLC/SharpVectors/blob/master/Source/SharpVectorRuntimeWpf/SvgDrawingCanvas.cs#L49) you will see the private modifier for the drawn objects. Via reflection it is possible to access and modify the items. Now you are able to make your own AttachedBehavior or custom binding! 😄👍
Upvotes: 3
Reputation: 9827
There must be multiple GeomtryDrawing
's in your svg XAML
like below :
<DrawingGroup>
<GeometryDrawing Brush="#FF71BF22">
<GeometryDrawing.Geometry>
<PathGeometry FillRule="Nonzero" Figures="M546.394,327.725L536.856,272.111 507.584,214.272C507.584,214.272,493.855,193.075,471.075,197.47L498.963,334.022 546.394,327.725z" />
</GeometryDrawing.Geometry>
</GeometryDrawing>
Search for all such Brush
in your code and change their values, thus creating two copies of your SVG XAML
, then using Trigger
swap these on MouseOver
.
EDIT #1 (based on OP's 1st comment)
You can use an AttachedProperty
to handle MouseEnter
and MouseLeave
events for your Path
. This AP allows you to set the transparency level.
Your Path
must be under Grid
.
public static byte GetSvgProp(DependencyObject obj)
{
return (byte)obj.GetValue(SvgPropProperty);
}
public static void SetSvgProp(DependencyObject obj, byte value)
{
obj.SetValue(SvgPropProperty, value);
}
// Using a DependencyProperty as the backing store for SvgProp. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SvgPropProperty =
DependencyProperty.RegisterAttached("SvgProp", typeof(byte), typeof(Window2), new PropertyMetadata((byte)0xFF, new PropertyChangedCallback(SvgPropChanged)));
private static void SvgPropChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((Grid)d).Loaded += (s, args) => {
var paths = ((Grid)s).Children.OfType<Path>();
foreach (Path p in paths)
{
p.MouseEnter += (s1, args1) => {
Path p1 = (Path)s1;
p1.Tag = p1.Fill; // save old value
var c = ((SolidColorBrush)p1.Fill).Color;
Color newColor = new Color() { A=(byte)e.NewValue, R = c.R, G = c.G, B = c.B };
p1.Fill = new SolidColorBrush() { Color = newColor };
};
p.MouseLeave += (s2, args2) => {
Path p2 = (Path)s2;
//p2.Fill.Opacity = 1.0;
p2.Fill = (Brush)p2.Tag; // revert back to old value
};
}
};
}
Assuming your SVG code is in a Grid
:
<Grid local:Window2.SvgProp="0x23">
<Path Fill="Red" Data="M311.517,14.053c-99.265,0-180.024,80.66-180.024,179.805c0,41.538,14.182,79.827,37.955,110.303L0,451.176l22.889,26.313 l170.577-147.994c31.628,27.496,72.926,44.168,118.051,44.168c99.266,0,180.025-80.661,180.025-179.805 C491.542,94.713,410.784,14.053,311.517,14.053z M311.517,353.663c-88.237,0-160.024-71.688-160.024-159.805 S223.279,34.053,311.517,34.053s160.025,71.688,160.025,159.805S399.755,353.663,311.517,353.663z"/>
<Polygon Points="322.447,122.812 300.587,122.812 300.587,182.928 240.471,182.928 240.471,204.788 300.587,204.788 300.587,264.904 322.447,264.904 322.447,204.788 382.563,204.788 382.563,182.928 322.447,182.928 " Fill="#000000"/>
</Grid>
Upvotes: 1