WPF pixel gridlines - c#

I'm trying to draw a grid on my canvas in which:
The lines are always one pixel thick
The size of the square tile are expressed in pixel or in other words the distance between each horizontal and vertical lines is in pixels and maybe binded to the code behind so that I can change it at run time.
This is my first attempt, but maybe I'm using the wrong controls.
<Canvas Panel.ZIndex="0" x:Name="TileCanvas">
<Grid Panel.ZIndex="5">
<Rectangle Width="{Binding ElementName=TileCanvas, Path=ActualWidth}" Height="{Binding ElementName=TileCanvas, Path=ActualHeight}"
Stroke="Black" StrokeThickness="0">
<Rectangle.Fill>
<DrawingBrush ViewportUnits="Absolute" TileMode="Tile">
<DrawingBrush.Viewport>
<MultiBinding Converter="{StaticResource RectConverter}">
<...>
</MultiBinding>
</DrawingBrush.Viewport>
<DrawingBrush.Drawing>
<DrawingGroup>
<GeometryDrawing Geometry="M0,0 L1,0 1,0.1, 0,0.1Z" Brush="Green" RenderOptions.BitmapScalingMode="NearestNeighbor"/>
<GeometryDrawing Geometry="M0,0 L0,1 0.1,1, 0.1,0Z" Brush="Green" RenderOptions.BitmapScalingMode="NearestNeighbor"/>
</DrawingGroup>
</DrawingBrush.Drawing>
<DrawingBrush.Transform>
<ScaleTransform ScaleX="1" ScaleY="1"/>
</DrawingBrush.Transform>
</DrawingBrush>
</Rectangle.Fill>
</Rectangle>
</Grid>
This solution allows me to vary the size of each tile, but:
I didn't find the way to fix the line thickness to one pixel
When I change the DrawingBrush.Viewport with the converter I do enlarge the tile (Great!) but the thickness of the lines increase (boo).

I had a very similar problem.
You can use a single geometry and if you want to avoid thickness increase\decrease you have to express the thickness in terms of the tile width by a ratio like thickness = 1/tileWidth. If you change that size of your tile with a WPF control you can use a converter to update the thickness accordingly.
<GeometryDrawing Geometry="M10,0 L10,10 0,10 10,10 10,0Z" Brush="Green" RenderOptions.BitmapScalingMode="NearestNeighbor"/>
<GeometryDrawing.Pen>
<Pen Thickness="{Binding ElementName=[TILE SIZE CONTROL VAL], Converter={StaticResource RatioConverter}}"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (1 / (double)value);
}

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.

Mandatory Use of Setting x:Shared="False" Not Possible

This Question might be Very Similar to Questions such as Error when using x:Shared="False" resources in external assembly in WPF but I have not been able to find a Solution that I can Relate to or rather get an Idea of How to Solve this.
Why I have mentioned Mandatory Use in the title is I have not been able to find an alternative way to solve my problem other than the with the use of Setting X:shared to false.
My problem is that in a particular view that has Icons , for Elements of Similar Type Icons seem to be sharing hence even if there are two or more types the Icon will only be rendered with one Item
This Question is justified in these Stack oveerflow Questions as well
Content Only being shown in a Single element at a given time
WPF: Can use StaticResource only once
I would Really appreciate any help/suggestions to overcome this
A complication is the numerous colours you have there. The trend nowadays is to simpler icons with just a background and foreground. Which you can "just" use one path and geometry for.
Seeing as how this is several shapes and several colours, you could use a DrawingImage.
I did this example in a usercontrol, it's roughly like one of your icons.
xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options"
mc:Ignorable="PresentationOptions"
>
<UserControl.Resources>
<DrawingImage x:Key='icon' PresentationOptions:Freeze="True">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Geometry="M17,17A5,5,0,0,1,12,22A5,5,0,0,1,7,17C7,15.36,7.79,13.91,9,13L9,5A3,3,0,0,1,12,2A3,3,0,0,1,15,5L15,13C16.21,13.91,17,15.36,17,17 M11,8L11,14.17C9.83,14.58,9,15.69,9,17A3,3,0,0,0,12,20A3,3,0,0,0,15,17C15,15.69,14.17,14.58,13,14.17L13,8 11,8z"
Brush="Wheat"
>
<GeometryDrawing.Pen>
<Pen Thickness="1" Brush="Green"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
<GeometryDrawing Geometry="M17,18L12,15.82 7,18 7,5 17,5 M17,3L7,3A2,2,0,0,0,5,5L5,21 12,18 19,21 19,5C19,3.89,18.1,3,17,3z"
Brush="Lavender"
>
<GeometryDrawing.Pen>
<Pen Thickness="1" Brush="Red"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</UserControl.Resources>
<Grid>
<StackPanel>
<Image Width="12" Height="12" Source="{StaticResource icon}"/>
<Image Width="12" Height="12" Source="{StaticResource icon}"/>
</StackPanel>
</Grid>
</UserControl>
I might look at using DataTemplates to create the icons, if for any reason x:Shared is a problem. A DataTemplate instantiates a copy of the content when it's applied, so sharing is a non-issue.
Resource:
<DataTemplate x:Key="FileSystemIcon">
<Canvas Width="12" Height="12">
<Path
Stroke="Black"
Fill="White"
Data="M20,4L4,4A2,2,0,0,0,2,6L2,18A2,2,0,0,0,4,20L20,20A2,2,0,0,0,22,18L22,6A2,2,0,0,0,20,4 M20,18L4,18 4,8 12,13 20,8 20,18 M20,6L12,11 4,6 4,6 20,6 20,6z"
/>
</Canvas>
</DataTemplate>
Usage:
<UserControl ContentTemplate="{StaticResource FileSystemIcon}" />

Using Vector images as an image source. WPF , C#

i'm working on a project including loads of images. the thing is, like the title says, i have to convert all my vector images to png before i can use them as a image source.
I have vector images created in illustrator. I have them in the .ai project file , how do i go from here ?
My goal is to be able to do this :
<Image Width="70" Height="70" Source="MyVectorImage"/>
If you want to get the ImageSource from a geometry path image into your cs file, you can put the drawingImage into a resource file: Icons.xaml:
<DrawingImage x:Key="hazelnut">
<DrawingImage.Drawing>
<DrawingGroup>
<GeometryDrawing Brush="Black">
<GeometryDrawing.Geometry>
<GeometryGroup>
<PathGeometry Figures="M 16.6309,18.6563C 17.1309,8.15625 29.8809,14.1563 29.8809,14.1563C 30.8809,11.1563 34.1308,11.4063 34.1308,11.4063C 33.5,12 34.6309,13.1563 34.6309,13.1563C 32.1309,13.1562 31.1309,14.9062 31.1309,14.9062C 41.1309,23.9062 32.6309,27.9063 32.6309,27.9062C 24.6309,24.9063 21.1309,22.1562 16.6309,18.6563 Z M 16.6309,19.9063C 21.6309,24.1563 25.1309,26.1562 31.6309,28.6562C 31.6309,28.6562 26.3809,39.1562 18.3809,36.1563C 18.3809,36.1563 18,38 16.3809,36.9063C 15,36 16.3809,34.9063 16.3809,34.9063C 16.3809,34.9063 10.1309,30.9062 16.6309,19.9063 Z ">
<PathGeometry.Transform>
<TransformGroup>
<ScaleTransform
CenterX="23"
CenterY="20"
ScaleX="0.45"
ScaleY="0.45" />
</TransformGroup>
</PathGeometry.Transform>
</PathGeometry>
</GeometryGroup>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
And add in you App.xaml:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Resources/Icons.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
And use it in your cs file like:
ImageSource image = ResourcePathToImageSource("hazelnut");
private ImageSource ResourcePathToImageSource(string resourcesName)
{
return (DrawingImage)Application.Current.TryFindResource(resourcesName);
}
You can use a DrawingImage as the Image's Source. DrawingImage uses a Geometry (i.e. vector graphics) instead of a bitmap.
<Image>
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<GeometryDrawing>
<GeometryDrawing.Pen>
<Pen Thickness="2" Brush="Black"/>
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="100,100,100,100"/>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
You can of course also bind the Source property to a view model property of type ImageSource, which contains a DrawingImage that you would create from your original vector data.

Best way to use a vector image in Viewport3D?

I was able to display a vector image with standard WPF like this.
<Image >
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<GeometryDrawing>
<GeometryDrawing.Pen>
<Pen Brush="#8F8E8F" Thickness="1" />
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<LineGeometry StartPoint="0,0" EndPoint="0,10"/>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
Unfortunately I was not able to do the same inside a Viewport3D element.
I created a VisualBrush from the Image and added it to the DiffuseMaterial of my 3D Model.
I also tried it via a DrawingBrush. Unfortunately the vector image gets renderd to a standard bitmap at some point of the pre-render processed. (that is what i think).
Is it even possible to display a vector image inside a Viewport3D?
Thank you for help in advance.

Not able to draw horizontal line on canvas if the value of x2 is more than 125020

I'm trying to draw lines on a canvas but i'm not able to draw it if the value of x2 is more than 125020. Please find the XAML code below.`I'm able to see lines if the value of x2 is equal to or below 125020.
<ScrollViewer Name="C1_S" Grid.Row="0" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" VerticalAlignment="Bottom" Grid.ColumnSpan="2" >
<Canvas Name="canvas_core0" Grid.Row="1" HorizontalAlignment="Right" VerticalAlignment="Bottom" Height="640" Width="1000000" MouseWheel="Canvas_MouseWheel" >
<Line Stroke="Black" X1="20" Y1="20" X2="20" Y2="620" StrokeEndLineCap="Triangle" StrokeDashCap="Triangle" />
<Line Stroke="Black" X1="20" Y1="220" X2="125021" Y2="220" StrokeEndLineCap="Triangle" StrokeDashCap="Triangle" />
<Line Stroke="Black" X1="20" Y1="420" X2="{Binding ElementName=canvas_core0, Path=Width}" Y2="420" StrokeEndLineCap="Triangle" StrokeDashCap="Triangle" />
<Line Stroke="Black" X1="20" Y1="620" X2="{Binding ElementName=canvas_core0, Path=Width}" Y2="620" StrokeEndLineCap="Triangle" StrokeDashCap="Triangle" />
<Canvas.Background>
<DrawingBrush TileMode="Tile" Viewport="0,20,40,40" ViewportUnits="Absolute">
<DrawingBrush.Drawing>
<GeometryDrawing>
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="0,0,50,50"/>
</GeometryDrawing.Geometry>
<GeometryDrawing.Pen>
<Pen Brush="Gray" Thickness=".1"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
</Canvas.Background>
<Canvas.RenderTransform>
<MatrixTransform/>
</Canvas.RenderTransform>
</Canvas>
</ScrollViewer>
Can anyone help? Is there any limit for the length of a line while drawing on a canvas?
Huh, must be a bug with WPF drawing long horizontal lines.
I don't have a real answer for you but a work around might be to NOT draw horizontal lines. Instead draw nearly horizontal lines. If you change Y1 or Y2, but not both, from "220" to "220.00001" then the line is visible. Note that "220.000001" (one more 0) did not draw so that seems to be another limit of some sort.
I tested it with X2="125021000" (added three 0s) and the line still showed up.
Increasing the StrokeThickness (even only slightly) works.
I realise this answer is somewhat unsatisfactory but may help if you are desperate and is at least a clue.
I tried playing with UseLayoutRounding and SnapsToDevicePixels but couldn't make it work.
Interesting.

Categories