Set InkCanvas Background DrawingBrush via C# - c#

I want to set the following XAML attributes via C#:
<InkCanvas.Background>
<DrawingBrush Stretch="None" TileMode="Tile" Viewport="0,0,2,2" ViewportUnits="Absolute">
<DrawingBrush.Drawing>
<DrawingGroup>
<GeometryDrawing Brush="White">
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="0,0,2,2" />
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing Brush="#FFE3E3E3">
<GeometryDrawing.Geometry>
<GeometryGroup>
<RectangleGeometry Rect="0,0,1,1" />
<RectangleGeometry Rect="1,1,1,1" />
</GeometryGroup>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</InkCanvas.Background>
How should I go about this?

I have found the solution myself and leave it here for anyone else, facing the same issue.
http://www.c-sharpcorner.com/uploadfile/mahesh/wpf-drawing-brush/ pretty much is what i was looking for.

Related

Is it possible to use WPF ResourceDictionary with parameters?

I have stored some icons as XAML-Code in the resourcedictionary, e.g.
<DataTemplate x:Key="Question">
<Viewbox Width="16" Height="16" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Rectangle Width="16" Height="16">
<Rectangle.Fill>
<DrawingBrush>
<DrawingBrush.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="#00FFFFFF" Geometry="F1M16,16L0,16 0,0 16,0z" />
<GeometryDrawing Brush="#FFF6F6F6" Geometry="F1M10,14L6,14 6,9C6,8.232,6.29,7.531,6.765,7L4,7 4,5C4,3.262 5.682,2 8,2 10.316,2 12,3.262 12,5L12,7C12,8.304,11.164,9.416,10,9.828z" />
<GeometryDrawing Brush="#FF414141" Geometry="F1M9,11L7,11 7,13 9,13z M9,10L7,10 7,9C7,7.897,7.897,7,9,7L9,5.203C8.84,5.115 8.495,5 8,5 7.504,5 7.159,5.115 7,5.203L7,6 5,6 5,5C5,3.841 6.261,3 8,3 9.738,3 11,3.841 11,5L11,7C11,8.103,10.102,9,9,9z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Rectangle.Fill>
</Rectangle>
</Viewbox>
</DataTemplate>
The problem: width and height are fixed values. So i changed the fixed values to "Auto" without any error in the resourcedictionary.
<DataTemplate x:Key="QuestionAuto">
<Viewbox Width="Auto" Height="Auto" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Rectangle Width="Auto" Height="Auto">
<Rectangle.Fill>
<DrawingBrush>
<DrawingBrush.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="#00FFFFFF" Geometry="F1M16,16L0,16 0,0 16,0z" />
<GeometryDrawing Brush="#FFF6F6F6" Geometry="F1M10,14L6,14 6,9C6,8.232,6.29,7.531,6.765,7L4,7 4,5C4,3.262 5.682,2 8,2 10.316,2 12,3.262 12,5L12,7C12,8.304,11.164,9.416,10,9.828z" />
<GeometryDrawing Brush="#FF414141" Geometry="F1M9,11L7,11 7,13 9,13z M9,10L7,10 7,9C7,7.897,7.897,7,9,7L9,5.203C8.84,5.115 8.495,5 8,5 7.504,5 7.159,5.115 7,5.203L7,6 5,6 5,5C5,3.841 6.261,3 8,3 9.738,3 11,3.841 11,5L11,7C11,8.103,10.102,9,9,9z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Rectangle.Fill>
</Rectangle>
</Viewbox>
</DataTemplate>
Then i used the icon in my view with setting the width and height values, but nothing is shown. the "fixed" icon works, the "auto" icon not.
<ContentPresenter Grid.RowSpan="2"
ContentTemplate="{StaticResource Question32}"
Margin="20,0">
</ContentPresenter>
vs.
<ContentPresenter Grid.RowSpan="2"
ContentTemplate="{StaticResource QuestionAuto}"
Margin="20,0"
Width="64"
Height="64">
</ContentPresenter>
Is it possible to set width and height parameter in the xaml-view and use them in the resourcedictionary? because the xaml-icon is basically "dynamic" and a variable size would be better than guessing the width and height to fit perfectly.
Better define the icons as DrawingImage resources like
<DrawingImage x:Key="Question">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="#00FFFFFF" Geometry="F1M16,16L0,16 0,0 16,0z" />
<GeometryDrawing Brush="#FFF6F6F6" Geometry="F1M10,14L6,14 6,9C6,8.232,6.29,7.531,6.765,7L4,7 4,5C4,3.262 5.682,2 8,2 10.316,2 12,3.262 12,5L12,7C12,8.304,11.164,9.416,10,9.828z" />
<GeometryDrawing Brush="#FF414141" Geometry="F1M9,11L7,11 7,13 9,13z M9,10L7,10 7,9C7,7.897,7.897,7,9,7L9,5.203C8.84,5.115 8.495,5 8,5 7.504,5 7.159,5.115 7,5.203L7,6 5,6 5,5C5,3.841 6.261,3 8,3 9.738,3 11,3.841 11,5L11,7C11,8.103,10.102,9,9,9z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
and show them in an Image element like
<Image Source="{StaticResource Question}" Width="64" Height="64"/>
The drawing would stretch to the desired size according to the Stretch property of the Image, which defaults to Uniform.

How to reuse a static GeometryDrawing in a DrawingImage using xaml

If I define in app.xaml a GeometryDrawing like this:
<GeometryDrawing x:Key="ReuseThis"
Pen="..."
Brush="..."
Geometry="..."/>
How can I then use it later in a DrawingImage like this:
<DrawingImage x:Key="FullImage">
<DrawingImage.Drawing>
<DrawingGroup>
<GeometryDrawing reuse it here somehow"{StaticResource ReuseThis}"/>
<Geometrydrawing ...>
<Geometrydrawing ...>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
I'm trying to avoid copying and pasting that GeometryDrawing in a bunch of DrawingImages I have.
Thanks
You can use the StaticResource Markup Extension in XAML Object Element Syntax:
<DrawingImage>
<DrawingImage.Drawing>
<DrawingGroup>
<StaticResource ResourceKey="ReuseThis"/>
<GeometryDrawing .../>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>

How to handle events in Custom Controls

I am trying to create a simple controller, here is my Generic.xaml;
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TopluNotEkle">
<Style TargetType="{x:Type local:FileSelector}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:FileSelector}">
<Button BorderThickness="8,8,8,8" Background="Gray" x:Name="MainButton">
<Button.BorderBrush>
<DrawingBrush TileMode="Tile" Viewport="0,0,64,64" ViewportUnits="Absolute">
<DrawingBrush.Drawing>
<DrawingGroup>
<GeometryDrawing Brush="LightGray">
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="0,0,100,100" />
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing Brush="DarkGray">
<GeometryDrawing.Geometry>
<GeometryGroup>
<RectangleGeometry Rect="0,0,50,50"/>
<RectangleGeometry Rect="50,50,50,50"/>
</GeometryGroup>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Button.BorderBrush>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="BlueViolet" FontWeight="Bold" FontSize="20">Drag & Drop</TextBlock>
</Button>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
and this is my code behind
public class FileSelector : Control
{
static FileSelector()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(FileSelector), new FrameworkPropertyMetadata(typeof(FileSelector)));
MainButton.Drop += myDrop;
}
static void myDrop(object sender, DragEventArgs e)
{
Debug.Fail("This is called");
}
}
I am getting The name MainButton does not exist in current context error. I also tried setting Drop = "myDrop", however, that also didn't work.
How can I listen to events on my component?
Buttons have been assigned a name by the x:Name attribute for us to be able to find them in code and hook up their click event handlers. This is done by overriding the OnApplyTemplate in our Custom Control class.
Retrieve the Button from the template
public override void OnApplyTemplate()
{
Button mainButton = GetTemplateChild("MainButton") as Button;
if (mainButton != null)
mainButton.Click += MainBtnClick;
}
Follow a complete tutorial like for example (but not necessarily) this: http://blog.magnusmontin.net/2013/03/16/how-to-create-a-custom-window-in-wpf/
So your problem is not what you are setting as a 'Drop' value, it is the reference to the MainButton that is not available.
I think you are trying to create a custom control, which typically defined as UserControl, not as a part of ResourceDictionary. I might be wrong as I haven't worked with WPF for several years. Here is how to create user control:
<UserControl x:class= "YourNamespace.FileSelector" ... other xmlns garbage>
<Button BorderThickness="8,8,8,8" Background="Gray" x:Name="MainButton">
<Button.BorderBrush>
<DrawingBrush TileMode="Tile" Viewport="0,0,64,64" ViewportUnits="Absolute">
<DrawingBrush.Drawing>
<DrawingGroup>
<GeometryDrawing Brush="LightGray">
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="0,0,100,100" />
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing Brush="DarkGray">
<GeometryDrawing.Geometry>
<GeometryGroup>
<RectangleGeometry Rect="0,0,50,50"/>
<RectangleGeometry Rect="50,50,50,50"/>
</GeometryGroup>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Button.BorderBrush>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="BlueViolet" FontWeight="Bold" FontSize="20">Drag & Drop</TextBlock>
</Button>
Also check out this tutorial: https://www.tutorialspoint.com/wpf/wpf_custom_controls.htm

How to specify the default value if the binding fails?

I have a DrawingBrush as follow :-
<DrawingBrush x:Key="MY_ICON" Viewbox="0,0,39.125,39.125" ViewboxUnits="Absolute">
<DrawingBrush.Drawing>
<GeometryDrawing Brush="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=uiEntityViews:BaseView}, Path=Color}" 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>
I used the above brush inside the style as the following:-
<Style x:Key="NODE_ICON" TargetType="Rectangle">
<Setter Property="Fill">
<Setter.Value>
<DrawingBrush TileMode="None">
<DrawingBrush.Drawing>
<DrawingGroup>
<GeometryDrawing Brush="{StaticResource MY_ICON}">
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="0,0,1,1" />
</GeometryDrawing.Geometry>
</GeometryDrawing>
<DrawingGroup>
<DrawingGroup.Transform>
<TranslateTransform X="0.2" Y="0.2" />
</DrawingGroup.Transform>
<GeometryDrawing Brush="{StaticResource NODE_ICON}">
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="0,0,1,1" />
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingGroup>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Setter.Value>
</Setter>
Right now, I am getting this error - System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='Views.UIEntityViews.BaseView', AncestorLevel='1''. BindingExpression:Path=Color; DataItem=null; target element is 'GeometryDrawing' (HashCode=3377278); target property is 'Brush' (type 'Brush').
It seems that the binding is not working. Is there a way to specify the default value for color, lets say <GeometryDrawing Brush="{StaticResource ROADM_ICON, color=Gray}"> if the binding fails?
Use FallbackValue.....<GeometryDrawing Brush="{StaticResource NODE_ICON, FallbackValue=Gray}">
As #Carmine suggested using FallbackValue, I was able to make it work making following changes:-
<GeometryDrawing Brush="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=uiEntityViews:CanvasLinkConnectionPointBaseView}, Path=MeSiteColor, FallbackValue=Gray}" 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">

How to use DrawingBrush as Window.Icon?

I have a DLL that has a ResourceDictionary containing a XAML image:
<DrawingBrush x:Key="imgFoo" ViewboxUnits="Absolute" Viewbox="0,0,128,128">
<DrawingBrush.Drawing>
<GeometryDrawing Brush="#FF111111">
<GeometryDrawing.Pen>
<Pen LineJoin="Miter" StartLineCap="Square" EndLineCap="Square"/>
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<PathGeometry Figures="M 56.5625 ... 64.03125 45.46875 z"
FillRule="NonZero"/>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
Is it possible to use this DrawingBrush as Window.Icon?
using StaticResource or DynamicResource doesn't work:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Icon="{DynamicResource imgFoo}">
The only thing I found is using Window.Resources like this:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Icon="{DynamicResource imgFoo}">
<Window.Resources>
<DrawingImage x:Key="imgFoo">
<DrawingImage.Drawing>
<GeometryDrawing Brush="#FF111111">
<GeometryDrawing.Pen>
<Pen LineJoin="Miter" StartLineCap="Square"
EndLineCap="Square"/>
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<PathGeometry Figures="M 56.5625 ... 64.03125 45.46875 z"
FillRule="NonZero"/>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingImage.Drawing>
</DrawingImage>
</Window.Resources>
But this uses only a part of the DrawingBrush from the DLL file and creates duplicate XAML code.
Any suggestions on how I could use that DrawingBrush directly?
You could split the resource declaration into two parts and declare the GeometryDrawing and the DrawingBrush separately:
<GeometryDrawing x:Key="imgFooDrawing" Brush="#FF111111">
<GeometryDrawing.Pen>
<Pen LineJoin="Miter" StartLineCap="Square" EndLineCap="Square"/>
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<PathGeometry Figures="M10,64 L64,10 118,64 64,118Z" FillRule="NonZero"/>
</GeometryDrawing.Geometry>
</GeometryDrawing>
<DrawingBrush x:Key="imgFoo" ViewboxUnits="Absolute" Viewbox="0,0,128,128"
Drawing="{StaticResource imgFooDrawing}">
</DrawingBrush>
Now you could directly reuse the GeometryDrawing in a DrawingImage that is used as the Window's Icon:
<Window.Icon>
<DrawingImage Drawing="{DynamicResource imgFooDrawing}"/>
</Window.Icon>
In case you can't change the Resource DLL, you could bind the DrawingImage's Drawing property to the Drawing property of the DrawingBrush.
This would however require an ugly workaround because you can't use a DynamicResource as binding source. You may set the Tag property of the Window to the DrawingBrush, and then create a RelativeSource/FindAncestor binding:
<Window ... Tag="{DynamicResource imgFoo}">
<Window.Icon>
<DrawingImage Drawing="{Binding Tag.Drawing,
RelativeSource={RelativeSource AncestorType=Window}}"/>
</Window.Icon>
</Window>

Categories