8

Hey everyone I have tried to sum up and come with the basic question and my idea which does not work so far :S

Basicly my question is: The user adds elements together, and I want to create a new element based on these figures, such that a new path can be made for the users defined element. Lets say I have a square and a triangle. The user combines this to a house. Now I want to make the house an element for the user. For this I need the path of the element, how do I create this?

My Idea The figure elements which are used are based on path strings. Therefore I want these to be converted to a geometry element that I can use later on. I use the code supplied by André Meneses in the answer below, the code replicated here:

public static Geometry PathMarkupToGeometry(ShieldGearViewModel shieldGearModelRec)
    {
        string pathMarkup = shieldGearModelRec.Gear.Path;
        try
        {
            string xaml =
            "<Path " +
            "xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>" +
            "<Path.Data>" + pathMarkup + "</Path.Data></Path>";
            var path = System.Windows.Markup.XamlReader.Load(xaml) as System.Windows.Shapes.Path;
            // Detach the PathGeometry from the Path
            if (path != null)
            {
                path.Height = shieldGearModelRec.Gear.Height;
                path.Width = shieldGearModelRec.Gear.Width;
                path.Fill = new SolidColorBrush(Colors.Green);
                path.Stretch = Stretch.Fill;
                Geometry geometry = path.Data;
                //Test not working, exception is thrown
                //Rect transRect = new Rect(shieldGearModelRec.Gear.x, shieldGearModelRec.Gear.y, shieldGearModelRec.Gear.Width, shieldGearModelRec.Gear.Height);
                //geometry.Transform.TransformBounds(transRect);
                path.Data = null;
                return geometry;
            }
            return null;
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex);
        }
        return null;
    }

This I do to get a Geometry to follow the example from this link describes. The problem with the above is that I cannot access x or y positions, of the new geometry element, so how do I specify this position?

For the position I think this link might be a solution, just haven't gotten it working yet? :)

When this is done I add it to a geometrygroup based on the before link, such that I can get a path, for the new element. But the geometrygroup has 0 as bounds. So for this to work I need to define x and y for the individual geometry elements, and then this might solve the geomtrygroup problem or I then have to look at this after :) Question has been standing for toooo long :|

TEXT BELOW IS THE OLD QUESTION AND THOUGHTS

I have a string that I would like to convert to a geometric shape in the code behind. So I found this on Stackoverflow WPF C# Path: How to get from a string with Path Data to Geometry in Code (not in XAML)

This link suggests that one can convert a string to path using parse with the following code:

var path = new Path();
path.Data = Geometry.Parse("M 100,200 C 100,25 400,350 400,175 H 280");

However parse is not available on Windows Phone. My other efforts has not solved the issue. I tried with pathGeometry but did not seem to be possible to set a string as the path?

So my problem is how to convert a string to a geometric shape in code behind not binding to an element on view.

First Step So I succeeded in creating a path with the following

var pathTesting = new System.Windows.Shapes.Path();
var b = new System.Windows.Data.Binding
{
    Source = DecorationOnShield[i].Gear.Path
};
System.Windows.Data.BindingOperations.SetBinding(pathTesting, System.Windows.Shapes.Path.DataProperty, b);

Now I am trying to convert the path to a geometric shape.

Extra

My idea is to do the same as this link describes. Where the example shows :

var blackRectGeometry = new RectangleGeometry();
Rect rct = new Rect();
rct.X = 80;
rct.Y = 167;
rct.Width = 150;
rct.Height = 30;
blackRectGeometry.Rect = rct;

But instead of rectangle I would like to use an arbitrary shape in form of a path, but still be able to set information such as coordinates and size.

Extra

I was thinking of defining a usercontrol which consisted of a path only looking like this:

<UserControl x:Class="UndoRedoShield.View.Geometry"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WP8"
mc:Ignorable="d"
Canvas.Left="{Binding Gear.x}" Canvas.Top="{Binding Gear.y}">


<Path Data="{Binding Gear.Path}" Fill="{Binding Gear.Color}" Stretch="Fill" UseLayoutRounding="False" Height="{Binding Gear.Height}" Width="{Binding Gear.Width}" Opacity="{Binding Gear.Opacity}">
    <Path.RenderTransform>
        <ScaleTransform ScaleX="{Binding Gear.Scale}" ScaleY="{Binding Gear.Scale}"/>
    </Path.RenderTransform>

</Path>

</UserControl>

But have not been able to use it in any way regarding geometry. Anyone have any idea using this method? Any method is appreciated ! :)

extra extra :)

Is it possible to create a geometric shape out of uielements, such that a usercontrol that is rendered Can be converted to a geometric Path?

Progress

I found this link Where I can create a geometry from a path. The path has the property width and height.

But the properties I do not have in geometry or path is the following:

  1. Canvas.Left
  2. Canvas.Top
  3. Canvas.ZIndex (I think this is possible when I add it to a GeometryGroup)

Seems like this can be done through the bounds property of the Path.Data. But not ZIndex. So this still needs to be tested with geometryGroup, and the Geometry needs to be added to the GeometryGroup.

Community
  • 1
  • 1
JTIM
  • 2,774
  • 1
  • 34
  • 74
  • 1
    Accourding to [MSDN](http://msdn.microsoft.com/en-us/library/system.windows.media.geometry.parse%28v=vs.110%29.aspx) 'Geometry.Parse' can be used on these platforms: Windows Phone 8.1, Windows Phone 8. Which version of windows phone are you developing? – Abolfazl Hosnoddin Apr 16 '14 at 13:56
  • Windows Phone 8, Probably will be upgrading to windows phone 8.1 at a later date. So the Geometry.Parse does not work? – JTIM Apr 16 '14 at 14:35
  • 1
    What do you mean by does not work? Your project type and version does not support it or by calling Parse method you do not get proper result? – Abolfazl Hosnoddin Apr 16 '14 at 14:50
  • It is not available. I have all updates I can access all Geometry objects but Geometry.Parse is not available. And I found a work around for this. So it is not really the issue. – JTIM Apr 16 '14 at 15:04

2 Answers2

7

Some time ago, while searching for a solution for this and I ended up creating this function. Maybe it will help you.

    public static Geometry PathMarkupToGeometry(string pathMarkup)
    {
        try
        {
            string xaml =
            "<Path " +
            "xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>" +
            "<Path.Data>" + pathMarkup + "</Path.Data></Path>";
            var path = XamlReader.Load(xaml) as Path;
            // Detach the PathGeometry from the Path
            if (path != null)
            {
                Geometry geometry = path.Data;
                path.Data = null;
                return geometry;
            }
            return null;
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex);
        }
        return null;
    }

Then I call this function like this:

     var arrow = new Path
     {
        Data = DesignHelpers.PathMarkupToGeometry("M-1,0 L0,1 L1,0"),
        Fill = new SolidColorBrush(Colors.Black),
        Stretch = Stretch.Fill,
        Height = 12,
        Width = 18,
        HorizontalAlignment = HorizontalAlignment.Center
    };

I don't know if this will fit your needs exactly but maybe it can help.

meneses.pt
  • 2,588
  • 3
  • 27
  • 38
  • I am still testing the code you supplied, and it seems to work. I however also need to specify x, y and z position of the element. Normally done with canvas properties. Do you have an idea for controlling this? The x and y properties are available in the bounds property but my debugger says they are only return values. – JTIM Aug 08 '14 at 09:49
  • After the arrow element is declared, you can do the following: `Canvas.SetTop(arrow, 10);` `Canvas.SetLeft(arrow, 20);` `Canvas.SetZIndex(arrow, 30);` And then you have to put the arrow element into a canvas for this to work, obviously... – meneses.pt Aug 08 '14 at 10:07
  • Okay then I think I am going about this wrong. Because I want to insert them into a geometrygroup as to create one element like this link in WPF http://www.c-sharpcorner.com/uploadfile/mahesh/path-in-wpf/ seems like I have not found the correct way to solve my problem yet then, damn :) – JTIM Aug 08 '14 at 10:11
  • But the Path is composed by a GeometryGroup, here you already have the Path. Why do you want to create a GeometryGroup if not to make a path? – meneses.pt Aug 08 '14 at 10:48
  • So I have many Usercontrols, with there form defined as paths. Then the user adds the elements together, and I want to create a new element based on these figures, such that a new path can be made for the users defined element. Lets say I have a square and a triangle. The user combines this to a house. Now I want to make the house an element for the user. For this I need the path of the element? – JTIM Aug 08 '14 at 10:53
  • Given your example, you have your triangle as a Path object and your square as a Path object, you add them to a new Canvas object, defining those properties (Top, Left, ZIndex), then you can add your canvas object to a ViewBox object and use that as a new control, or put that into a usercontrol. does this help you? – meneses.pt Aug 08 '14 at 11:05
  • Yes, this might be the simplest approach, but to maintain the system and using the same views and lists, it would be best if it was possible to create a new path based on this shape. Such that it becomes one object following the same rules and the new object maintains the same properties. Therefore I am trying to create the geometrygroup, your code made it possible to create the geometry element, and I can add them to a geometrygroup but the bounds are zero for this group. And the second problem is the positioning of the square and triangle, in respect to the house example. – JTIM Aug 08 '14 at 11:08
  • I guess what you want to exactly achieve is not quite possible. The closest thing you would be able to achieve is to give the X and Y coordinates in the path string, as start coordinates or as a translation (don't even know if that is possible), but then you would still have the Z-index problem. I guess you should start thinking outside the box and look for an alternate way to achieve what you want. This seems kind of a dead-end. :( – meneses.pt Aug 08 '14 at 11:19
  • Damn, I tried with translation after I created the geometry element as you suggested but was not possible, just through an exception of inaccessible so no help there :S damn, I will have to try to think more about it then. :| – JTIM Aug 08 '14 at 11:21
  • Would it be possible to include canvas.x canvas.y and so forth in the xaml markup as you showed with the path? – JTIM Aug 09 '14 at 09:58
  • But what will happen when I insert it in a geometrygroup? Then the bounds of the arrow object would have an x and y value which might make it possible to get the correct elememt shown as geometrygroup? I have not been able to set it can you show it in the example? – JTIM Aug 09 '14 at 15:47
  • It does not seem that the position is kept when setting geometry = path.Data – JTIM Aug 09 '14 at 19:48
3

Geometry.Parse (and as far as I can tell, it's back-end StreamGeometry) is indeed missing from the Windows Phone platform, but according to this page: http://msdn.microsoft.com/en-us/library/ms752293(v=vs.110).aspx

WPF provides two classes that provide mini-languages for describing geometric paths: StreamGeometry and PathFigureCollection.

PathFigureCollection is available for Windows Phone, so this looks like the place to check:

http://msdn.microsoft.com/en-us/library/windowsphone/develop/system.windows.media.pathfigure(v=vs.105).aspx

Now you just need to be able to create PathGeometry from the XAML-style markup. It looks like there are examples here for generating a Path from the XAML syntax:

Convert XAML PathGeometry to WPF PathGeometry

Windows Phone 7: How to parse Bezier Path string like in XAML?

Basically something like

string data = "M 100,200 C 100,25 400,350 400,175 H 280";
Path path = XamlReader.Load("<Path Data='" + data + "'/>") as Path;
Community
  • 1
  • 1
steve cook
  • 3,116
  • 3
  • 30
  • 51
  • Thank you. Maybe this is a better way to make the path. But regarding creating geometry, enables me to set all kind of variables as position. Since i cannot test it now, you say that this is possible with pathfigurecollection or pathgeometry? – JTIM Apr 23 '14 at 06:09
  • 1
    You should be able to set anything that you would be able to set via XAML. The main restriction with this technique seems to be that you cannot edit/alter the path after it has been created. – steve cook Apr 23 '14 at 16:28
  • Finally had time to test this. And does not seem to work. The link you refer to seems to be that you have access to the xaml code, and the way you refer, but I do not want to specify the xaml code. The first step I showed in my question gets a path that I bind to a variable of type System.Windows.Shapes.Path. With this I want to create a figure or geometry. But seems not to be possible with the links and solutions you suggested. – JTIM Apr 26 '14 at 16:41
  • The XAML code is just a wrapper around your path description. I've updated the example. – steve cook Apr 28 '14 at 01:52