How to bind PathGeometry objects in MVVM - c#

Imagine an application where the user can type in some text and based on the text input different symbols are shown on an image.
I am looking for a way generate a list of Path objects and bind this list in XAML to show the path objects on top of another path-image.
I.e. I have a simple image of a house, the user type in text like:
"ball on roof, flower in window, shovel in garden"
In the ViewModel I will analyze this text and generate a path Circle for the ball, a path Star for the flower and a path Square for the shovel.
I think these objects should be put in a List and in XAML bind to this list.
The "house" is drawn like this:
<Border Grid.Column="1" CornerRadius="10" BorderBrush="Black" BorderThickness="0.3" Margin="5,0,0,0" Grid.RowSpan="2" Padding="5">
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Stretch="Uniform">
<Grid RenderTransformOrigin="0.5,0.5">
<Grid.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleY="-1" ScaleX="1"/>
<SkewTransform AngleY="0" AngleX="0"/>
<RotateTransform Angle="0"/>
<TranslateTransform/>
</TransformGroup>
</Grid.RenderTransform>
<Path Fill="Black" Data="{StaticResource Path1}"/>
<Path Fill="Black" Data="{StaticResource Path2}"/>
<Path Fill="Black" Data="{StaticResource Path3}"/>
<Path Fill="Black" Data="{StaticResource Path4}"/>
...
</Grid>
</Viewbox>
</Border>
After the all the "Path" I imagine I would use a CombinedGeometry and bind to the VM List. But I am not sure about this part.

Related

making a Question mark in WPF

I am using the expression Blender 2010 draw in WPF and I am trying to make a question mark. This is what I have so far and it looks bad:
<ed:Arc Canvas.Left="33" Width="28" Height="24" Canvas.Top="22" ArcThickness="6" StartAngle="-45" EndAngle="140" Stretch="None" Fill ="Red" />
<ed:Arc Canvas.Left="45" Width="28" Height="26" Canvas.Top="37" ArcThickness="6" StartAngle="90" EndAngle="180" Stretch="None" Fill ="Red" RenderTransformOrigin="0.498,0.458" >
<ed:Arc.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="-179.625"/>
<TranslateTransform X="0.104" Y="1.427"/>
</TransformGroup>
</ed:Arc.RenderTransform>
</ed:Arc>
<Rectangle Canvas.Left="46" Canvas.Top="46" Width="6" Height="19" Stretch="Fill" Fill="Red" />
<Ellipse Canvas.Left="46" Width="6" Height="6" Canvas.Bottom="20" Fill="Red" Canvas.Top="70" RenderTransformOrigin="-0.477,-0.363" />
[enter image description here][1]
Updated: I just tried this :
<Path x:Name="Information" Canvas.Left="25" Canvas.Top="25" Stretch="Fill" Width="50" Height="50" Data="M9,89a81,81 0 1,1 0,2zm51-14c0-13 1-19 8-26c7-9 18-10 28-8c10,2 22,12 22,26c0,14-11,19-15,22c-3,3-5,6-5,9v22m0,12v16">
<Path.Fill>
<SolidColorBrush Color="Lime"/>
</Path.Fill>
</Path>
but it still look bad really bad[enter image description here][2]
please see up picture.
I got the information for the Sgv from
https://commons.m.wikimedia.org/wiki/Category:SVG_Question_marks
[1]: https://i.stack.imgur.com/A9X6A.png
[2]: https://i.stack.imgur.com/HKY6e.png
Looks like you are wanting to set up using paths in your WPF project.
Here is one example of doing this. There are many.
You can get your paths for example from Material Designs just click on an icon and then look at the SVG or XAML canvas where they have the Path.Data information.
For example below I have copied the data for a question mark and added it to a Viewbox. These ViewBox elements you can have in your Window.Resources or in a Resource file.
<Viewbox x:Key="questionMark">
<Canvas Width="512"
Height="512">
<Canvas.RenderTransform>
<TranslateTransform X="0"
Y="0" />
</Canvas.RenderTransform>
<Canvas.Resources />
<Canvas>
<Path xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Fill="Black"
Opacity="1.00">
<Path.Data>
<PathGeometry Figures="M10,19H13V22H10V19M12,2C17.35,2.22 19.68,7.62 16.5,11.67C15.67,12.67 14.33,13.33 13.67,14.17C13,15 13,16 13,17H10C10,15.33 10,13.92 10.67,12.92C11.33,11.92 12.67,11.33 13.5,10.67C15.92,8.43 15.32,5.26 12,5A3,3 0 0,0 9,8H6A6,6 0 0,1 12,2Z"
FillRule="NonZero" />
</Path.Data>
</Path>
</Canvas>
</Canvas>
</Viewbox>
To Use it you just add a Grid;
<Grid Background="Yellow" Width="50" Height="50">
<Grid.OpacityMask>
<VisualBrush Visual="{StaticResource questionMark}" />
</Grid.OpacityMask>
</Grid>
Result looks like this;

How to use the XAML dictionary that Syncfusion Metro Studio produces

For resolution independence we want scaling art. Ok, so a common source for that mentioned on stack is Syncfusion Metro Studio.
Metro Studio 2 produces this for XAML:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Viewbox x:Key="error">
<Grid Width="64" Height="64" Visibility="Visible">
<Grid Visibility="Visible">
<Rectangle Fill="#FFD21818" Visibility="Visible" />
<Ellipse Fill="#FFD21818" Visibility="Collapsed" />
<Path Data="M50.5,4.7500001C25.232973,4.75 4.75,25.232973 4.7500001,50.5 4.75,75.767029 25.232973,96.25 50.5,96.25 75.767029,96.25 96.25,75.767029 96.25,50.5 96.25,25.232973 75.767029,4.75 50.5,4.7500001z M50.5,0C78.390381,0 101,22.609621 101,50.5 101,78.390381 78.390381,101 50.5,101 22.609621,101 0,78.390381 0,50.5 0,22.609621 22.609621,0 50.5,0z" Stretch="Fill" Fill="#FFD21818" Visibility="Collapsed" />
</Grid>
<Path Data="F1M54.0573,47.8776L38.1771,31.9974 54.0547,16.1198C55.7604,14.4141 55.7604,11.6511 54.0573,9.94531 52.3516,8.23962 49.5859,8.23962 47.8802,9.94531L32.0026,25.8229 16.1224,9.94531C14.4167,8.23962 11.6511,8.23962 9.94794,9.94531 8.24219,11.6511 8.24219,14.4141 9.94794,16.1198L25.8255,32 9.94794,47.8776C8.24219,49.5834 8.24219,52.3477 9.94794,54.0534 11.6511,55.7572 14.4167,55.7585 16.1224,54.0534L32.0026,38.1745 47.8802,54.0534C49.5859,55.7585 52.3516,55.7572 54.0573,54.0534 55.7604,52.3477 55.763,49.5834 54.0573,47.8776z" Stretch="Uniform" Fill="#FFFFFFFF" Width="36" Height="36" Margin="0,0,0,0" RenderTransformOrigin="0.5,0.5">
<Path.RenderTransform>
<TransformGroup>
<TransformGroup.Children>
<RotateTransform Angle="0" />
<ScaleTransform ScaleX="1" ScaleY="1" />
</TransformGroup.Children>
</TransformGroup>
</Path.RenderTransform>
</Path>
</Grid>
</Viewbox>
</ResourceDictionary>
So far so good, just merge this into the project resources. But how to consume this?
using viewbox in ResourceDictionary file has an answer that lets you change the ViewBox to DataTemplate in the ResourceDictionary and then use a converter to display it as a button's ContentTemplate. That is ok for Button based stuff, but what if I just need the icon itself. How do I go from ViewBox in a resource dictionary to somehow including it in lets say a grid in XAML?
You can use it as Content for any ContentControl Directly,in case if you just want the icon in Grid,try like below,
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Viewbox x:Key="error">
<Grid Width="64" Height="64" Visibility="Visible">
<Grid Visibility="Visible">
<Rectangle Fill="#FFD21818" Visibility="Visible" />
<Ellipse Fill="#FFD21818" Visibility="Collapsed" />
<Path Data="M50.5,4.7500001C25.232973,4.75 4.75,25.232973 4.7500001,50.5 4.75,75.767029 25.232973,96.25 50.5,96.25 75.767029,96.25 96.25,75.767029 96.25,50.5 96.25,25.232973 75.767029,4.75 50.5,4.7500001z M50.5,0C78.390381,0 101,22.609621 101,50.5 101,78.390381 78.390381,101 50.5,101 22.609621,101 0,78.390381 0,50.5 0,22.609621 22.609621,0 50.5,0z" Stretch="Fill" Fill="#FFD21818" Visibility="Collapsed" />
</Grid>
<Path Data="F1M54.0573,47.8776L38.1771,31.9974 54.0547,16.1198C55.7604,14.4141 55.7604,11.6511 54.0573,9.94531 52.3516,8.23962 49.5859,8.23962 47.8802,9.94531L32.0026,25.8229 16.1224,9.94531C14.4167,8.23962 11.6511,8.23962 9.94794,9.94531 8.24219,11.6511 8.24219,14.4141 9.94794,16.1198L25.8255,32 9.94794,47.8776C8.24219,49.5834 8.24219,52.3477 9.94794,54.0534 11.6511,55.7572 14.4167,55.7585 16.1224,54.0534L32.0026,38.1745 47.8802,54.0534C49.5859,55.7585 52.3516,55.7572 54.0573,54.0534 55.7604,52.3477 55.763,49.5834 54.0573,47.8776z" Stretch="Uniform" Fill="#FFFFFFFF" Width="36" Height="36" Margin="0,0,0,0" RenderTransformOrigin="0.5,0.5">
<Path.RenderTransform>
<TransformGroup>
<TransformGroup.Children>
<RotateTransform Angle="0" />
<ScaleTransform ScaleX="1" ScaleY="1" />
</TransformGroup.Children>
</TransformGroup>
</Path.RenderTransform>
</Path>
</Grid>
</Viewbox>
</ResourceDictionary>
<Grid>
<ContentControl Content="{StaticResource error}"/>
</Grid>
if you are intend to use the same resource in multiple location,please set x:Shared attribute as false as below,
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Viewbox x:shared="false" x:Key="error">
.......
</Viewbox>
</ResourceDictionary>
I did a similar thing in one of my projects using Syncfusion Metro Studio. I found wrapping the image in a ViewBox caused a number of annoyances. I ended up using the image alone, and then embedded it into a Path where I wanted to use the image.
I found it a lot more flexible than trying to squeeze a ViewBox into xaml.
How I did it:
There is a type Geometry, which allows you to define a Bezier path as a resource:
<Geometry x:Key="Keyboard">M48.537998,24.254L57.365002,24.254 57.365002,30.875 48.537998,30.875z M17.642,24.254L46.332001,24.254 46.332001,30.875 17.642,30.875z M6.6760006,24.254L15.504,24.254 15.504,30.875 6.6760006,30.875z M50.744999,15.426L57.365002,15.426 57.365002,22.047001 50.744999,22.047001z M41.986,15.426L48.606998,15.426 48.606998,22.047001 41.986,22.047001z M33.09,15.426L39.709999,15.426 39.709999,22.047001 33.09,22.047001z M24.261999,15.426L30.882999,15.426 30.882999,22.047001 24.261999,22.047001z M15.435,15.426L22.056,15.426 22.056,22.047001 15.435,22.047001z M6.6070004,15.426L13.229,15.426 13.229,22.047001 6.6070004,22.047001z M50.744999,6.599L57.365002,6.599 57.365002,13.219 50.744999,13.219z M41.986,6.599L48.606998,6.599 48.606998,13.219 41.986,13.219z M33.09,6.599L39.709999,6.599 39.709999,13.219 33.09,13.219z M24.261999,6.599L30.882999,6.599 30.882999,13.219 24.261999,13.219z M15.435,6.599L22.056,6.599 22.056,13.219 15.435,13.219z M6.6070004,6.599L13.229,6.599 13.229,13.219 6.6070004,13.219z M4.47015,4.4635506L4.47015,33.242199 59.6413,33.242199 59.6413,4.4635506z M1.3333101,0L62.666698,0C63.403,0,64,0.59634399,64,1.3333397L64,36.166698C64,36.903702,63.403,37.5,62.666698,37.5L1.3333101,37.5C0.59704602,37.5,0,36.903702,0,36.166698L0,1.3333397C0,0.59634399,0.59704602,0,1.3333101,0z</Geometry>
Once you have a geometry resource you can use it in Path.Data. In this example the border is the bounds of the image 32x32 pixels. Then you can use the Border and use it in a Grid as you would with any other control.
<Border Width="32" Height="32">
<Path Data="{StaticResource Keyboard}" Fill="White" Stretch="Uniform" RenderTransformOrigin="0.5, 0.5">
</Path>
</Border>
This technique also allows you to bind the properties as needed. I.e. Fill to a color, and have it change dynamically.
Simply import the output from Metro Studio into Expression Blend
-> Design View
Select icon and click 'Tools' -> Make Brush Resource -> MakeDrawingBrush
Then Blend will convert the icon for use anywhere in your app

How can I get geometry information in C# from an XAML object?

given the following XAML code:
<Canvas Name="MainView">
<Canvas Name="TriangleElement" Width="50" Height="50" Canvas.Left="110" Canvas.Top="100">
<Canvas.RenderTransform>
<RotateTransform CenterX="25" CenterY="25" Angle="0" />
</Canvas.RenderTransform>
<Path Stroke="#FF009600" StrokeThickness="1" Fill="#FF68E168">
<Path.Data>
M 0,0 L 50,0 50,50 Z
</Path.Data>
</Path>
</Canvas>
<Canvas Name="SquareElement" Width="50" Height="50" Canvas.Left="170" Canvas.Top="100">
<Canvas.RenderTransform>
<RotateTransform CenterX="25" CenterY="25" Angle="0" />
</Canvas.RenderTransform>
<Path Stroke="#FF005DFF" StrokeThickness="1" Fill="#FF98D0F8">
<Path.Data>M 0,0 L 50,0 50,50 0,50 Z</Path.Data>
</Path>
</Canvas>
</Canvas>
How can I get the path data / geometry information in c# without naming it in the XAML? In the past I have created several UserControl's, created an interface to the objects, and pulled the info based on the Path name. In my current case I cannot use this approach.
Not sure if I understand the question, but can't you use
((Path)TriangleElement.Children[0]).Data
And what are those Canvas elements for? They don't seem to be doing anything.
Why not:
<Path Name="SquareElement" Width="50" Height="50" Stroke="#FF005DFF" StrokeThickness="1" Fill="#FF98D0F8">
<Path.RenderTransform>
<RotateTransform CenterX="25" CenterY="25" Angle="60" />
</Path.RenderTransform>
<Path.Data>M 0,0 L 50,0 50,50 0,50 Z</Path.Data>
</Path>
Then you can get straight to your paths by name.

about TranslateTransform and RenderTransformOrigin

I am using Silverlight 3.0 + .Net 3.5 + VSTS 2008 + C# to silverlight application.
I want to learn TranslateTransform and RenderTransformOrigin, could anyone recommend me some tutorials? I am a newbie of this area. And I did not find anything which is good to learn for a newbie from MSDN (correct me if there are some good stuff). :-)
BTW: I am headache about the coordination transformation matrix, it is great if the tutorial could cover this topic.
EDIT: here is the code which I am confused.
<Grid Margin="-1,0,100,0" x:Name="controlsContainer" Height="35" RenderTransformOrigin="0.5,0.5" VerticalAlignment="Bottom">
<Grid.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform Y="0"/>
</TransformGroup>
</Grid.RenderTransform>
<Rectangle Margin="0,0,0,0" Height="35" VerticalAlignment="Top" Fill="#97000000" Stroke="#00000000" RenderTransformOrigin="0.5,0.5"/>
<VideoPlayer:mediaControl Height="35" Margin="1,0,0,0" HorizontalAlignment="Stretch" VerticalAlignment="Top" x:Name="mediaControls" Visibility="Visible"/>
</Grid>
First of all translation does not use an origin so the RenderTransformOrigin does not apply to a TranslateTransform.
To learn about transforms why not try them out? Place a shape two times in a grid, and let the top one be transparent. Then transform the top shap and view the effect. Here I have rotated a rectangle by 45 degrees around the center of the rectangle.
<Grid Background="White">
<Rectangle Width="50" Height="50" Fill="Black"/>
<Rectangle Width="50" Height="50" Fill="Red" Opacity="0.5"
RenderTransformOrigin="0.5, 0.5">
<Rectangle.RenderTransform>
<RotateTransform Angle="45"/>
</Rectangle.RenderTransform>
</Rectangle>
</Grid>
Translate is specifically referred to by MSDN as Move. Refer to section to get a visual understanding of Transformations and Coordinate Systems.
Moves (translates) an element by the specified X and Y amounts.
alt text http://i.msdn.microsoft.com/dynimg/IC212086.png

Rendering sharp lines in WPF

If I render the following:
<Grid>
<Canvas SnapsToDevicePixels="True">
<Path Fill="#FF000000" SnapsToDevicePixels="True" Data="M 0.00,0.00 L 2.50,0.00 0.00,10.00 " />
<Path Fill="#FF260014" SnapsToDevicePixels="True" Data="M 2.50,0.00 L 7.50,0.00 2.50,10.00 0.00,10.00 " />
<Canvas.RenderTransform>
<ScaleTransform ScaleX="{Binding ElementName=slider,Path=Value}" ScaleY="{Binding ElementName=slider,Path=Value}" />
</Canvas.RenderTransform>
</Canvas>
<Slider x:Name="slider" Minimum="0" Maximum="50" Value="30"/>
</Grid>
I get this result (Kaxaml):
Notice the thin white line between the two shapes. I searched around and found out this has to do with pixel alignment. I would expect that settings SnapsToDevicePixels="True" would be enough to get rid of the line, but this doesn't work!
Any ideas how to get rid of the white line?
Try turning edge aliasing on with RenderOptions, like this (see Grid properties)
<Grid RenderOptions.EdgeMode="Aliased">
<Canvas SnapsToDevicePixels="True">
<Path Fill="#FF000000" SnapsToDevicePixels="True" Data="M 0.00,0.00 L 2.50,0.00 0.00,10.00 " />
<Path Fill="#FF260014" SnapsToDevicePixels="True" Data="M 2.50,0.00 L 7.50,0.00 2.50,10.00 0.00,10.00 " />
<Canvas.RenderTransform>
<ScaleTransform ScaleX="{Binding ElementName=slider,Path=Value}" ScaleY="{Binding ElementName=slider,Path=Value}" />
</Canvas.RenderTransform>
</Canvas>
<Slider x:Name="slider" Minimum="0" Maximum="50" Value="30"/>
</Grid>
Remember that SnapsToDevicePixels only controls that individual points do not lie on fractional pixel values. For horizontal and vertical lines this is most easily observed. In your case you are seeing an entirely different problem. The edges of your shapes are anti-aliased and therefore blended with the background. Since your shapes are exactly adjacent to each other both will be blended with the white background of the window. You can try putting one shape behind the other instead:
<Canvas>
<Path Fill="#FF000000" Data="M 0.00,0.00 L 7.50,0.00 2.50,10.00 0.00,10.00 " />
<Path Fill="#FF260014" Data="M 2.50,0.00 L 7.50,0.00 2.50,10.00 0.00,10.00 " />
<Canvas.RenderTransform>
<ScaleTransform ScaleX="{Binding ElementName=slider,Path=Value}" ScaleY="{Binding ElementName=slider,Path=Value}" />
</Canvas.RenderTransform>
</Canvas>
which should render correctly. You see similar rendering errors in many vector file formats that render primarily to screen, such as SVG.
The other option would be to turn off anti-aliasing but that will make your edges jaggy which may not be what you want (anti-aliasing turned off in the upper half):

Categories

Resources