Read StrokeDashArray property from XML file

Hi !

I would like to know how to save/load StrokeDashArray property from xml…Steps that I did, and I can´t see StrokeDashArray:
Thanks!

Step 1: Changed FlowChart.xml file:


Step 2: Changed MyNodeData class

//The data class representing nodes.
public class MyNodeData : GraphLinksModelNodeData
{
// The shape of each node
public NodeFigure Figure
{
get { return _Figure; }
set
{
if (_Figure != value)
{
NodeFigure old = _Figure;
_Figure = value;
RaisePropertyChanged(“Figure”, old, value);
}
}
}
private NodeFigure _Figure = NodeFigure.Rectangle;

    public int StrokeDashArray
    {
        get { return _StrokeDashArray; }
        set
        {
            int old = _StrokeDashArray;
            if (old != value)
            {
                _StrokeDashArray = value;
                RaisePropertyChanged("StrokeDashArray", old, value);
            }
        }
    }
    private int _StrokeDashArray = 2;

    // note that adding properties here means also adding lines to MakeXElement and LoadFromXElement

    public override XElement MakeXElement(XName n)
    {
        XElement e = base.MakeXElement(n);
        e.Add(XHelper.AttributeEnum<NodeFigure>("Figure", this.Figure, NodeFigure.Rectangle));
        e.Add(XHelper.Attribute("StrokeDashArray", this.StrokeDashArray, 2));


        return e;
    }

    public override void LoadFromXElement(XElement e)
    {
        base.LoadFromXElement(e);
        this.Figure = XHelper.ReadEnum<NodeFigure>("Figure", e, NodeFigure.Rectangle);
        this.StrokeDashArray = XHelper.Read("StrokeDashArray", e, 2);
    }
}

Step 3: Changed palette’s model’s data

// set up the model for the Palette
var paletteModel = new GraphLinksModel<MyNodeData, String, String, MyLinkData>();

        // this creates the palette's model's data in code:
        paletteModel.NodesSource = new List<MyNodeData>() {
            new MyNodeData() { Key="Comment",  Text="Comment",  Category="Comment", Figure=NodeFigure.Rectangle, StrokeDashArray=2 },
            new MyNodeData() { Key="Start",    Text="Start",    Category="Start", Figure=NodeFigure.RoundedRectangle,StrokeDashArray=2 },
            new MyNodeData() { Key="Step",     Text="Step",     Category="Standard", Figure=NodeFigure.Rectangle, StrokeDashArray=2 },
            new MyNodeData() { Key="Input",    Text="Input",    Category="Standard", Figure=NodeFigure.Input, StrokeDashArray=2 },
            new MyNodeData() { Key="Output",   Text="Output",   Category="Standard", Figure=NodeFigure.Output, StrokeDashArray=2 },
            new MyNodeData() { Key="Conditional", Text="?",     Category="Standard", Figure=NodeFigure.Diamond, StrokeDashArray=2 },
            new MyNodeData() { Key="Read",     Text="Read",     Category="Standard", Figure=NodeFigure.Ellipse , StrokeDashArray=2},
            new MyNodeData() { Key="Write",    Text="Write",    Category="Standard", Figure=NodeFigure.Ellipse, StrokeDashArray=2 },
            new MyNodeData() { Key="ManualOperation", Text="Manual Operation", Category="Standard", Figure=NodeFigure.ManualOperation, StrokeDashArray=2 },
            new MyNodeData() { Key="DataBase", Text="DataBase", Category="Standard", Figure=NodeFigure.Database, StrokeDashArray=2 },
            new MyNodeData() { Key="End",      Text="End",      Category="End", Figure=NodeFigure.RoundedRectangle, StrokeDashArray=2 }
          };


        myPalette.Model = paletteModel;

        // set up an initial model for the Diagram
        var model = new GraphLinksModel<MyNodeData, String, String, MyLinkData>();

        // and initialize it from the XML file that is an embedded resource
        String xml = WpfApplication1.MainWindow.Instance.LoadText("FlowChart", "xml");
        model.Load<MyNodeData, MyLinkData>(XElement.Parse(xml), "MyNodeData", "MyLinkData");
        model.Modifiable = true;
        model.HasUndoManager = true;
        myDiagram.Model = model;

Step 4: Changed DataTemplate: x:Key=“LinkTemplate” in XAML file, inserted: StrokeDashArray="{Binding Path=Data.StrokeDashArray}"

The Type of StrokeDashArray is not int but IEnumerable. So you need to change the declaration in your link data class and in the calls to the XHelper methods.

Hello Walter,

Please, can you help me? Can you modify my 4 steps ? I tried here, but with no success, …not read StrokeDashArray .

Thank you very much.

What´s wrong in this code? because thec orrect value was not load…

//The data class representing nodes.
public class MyNodeData : GraphLinksModelNodeData
{

    public IEnumerable<Double> StrokeDashArray
    {
        get { return _StrokeDashArray; }
        set
        {
            IEnumerable<Double> old = _StrokeDashArray;
            if (old != value)
            {
                _StrokeDashArray = value;
                RaisePropertyChanged("StrokeDashArray", old, value);
            }
        }
    }
    private IEnumerable<Double> _StrokeDashArray = new Double[1] { 2 };



    // note that adding properties here means also adding lines to MakeXElement and LoadFromXElement

    public override XElement MakeXElement(XName n)
    {
        XElement e = base.MakeXElement(n);
        e.Add(XHelper.AttributeEnum<NodeFigure>("Figure", this.Figure, NodeFigure.Rectangle));
        e.Add(XHelper.Attribute("StrokeDashArray", this.StrokeDashArray, new Double[1] { 2 }));


        return e;
    }

    public override void LoadFromXElement(XElement e)
    {
        base.LoadFromXElement(e);
        this.Figure = XHelper.ReadEnum<NodeFigure>("Figure", e, NodeFigure.Rectangle);
        this.StrokeDashArray = XHelper.Read("StrokeDashArray", e, new Double[1] { 2 });

    }
}

XML file:


    <DataTemplate x:Key="LinkTemplate">
        <go:LinkPanel go:Part.Reshapable="True">
            <go:Link.Route>
                <go:Route Routing="AvoidsNodes" Curve="JumpOver" Curviness="10" RelinkableFrom="True" RelinkableTo="True" />
            </go:Link.Route>
            <Polygon Fill="Black" Points="0 0  8 4  0 8  3 4" go:LinkPanel.Index="-1" go:LinkPanel.Alignment="1 0.5" go:LinkPanel.Orientation="Along" />
            <go:LinkShape x:Name="MyLinkShape" Stroke="Black" StrokeThickness="1"  StrokeDashArray="{Binding Path=Data.StrokeDashArray}" />
           
            <!-- this is the label that is only shown when connected to a Decision node -->
            <go:NodePanel Sizing="Auto" go:LinkPanel.Index="1" go:LinkPanel.Alignment="0 0 2 2" go:LinkPanel.Orientation="None">
                <Path go:NodePanel.Figure="None" />
                <TextBlock Text="{Binding Path=Data.Text, Mode=TwoWay}" TextWrapping="Wrap" go:Part.TextEditable="True" Visibility="{Binding Path=Link, Converter={StaticResource theLabelVisibilityConverter}}"/>
            </go:NodePanel>
            
        </go:LinkPanel>
    </DataTemplate>





    <go:Diagram x:Name="myDiagram"  Grid.Column="2" Padding="10" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch"
            NodeTemplateDictionary="{StaticResource NodeTemplateDictionary}" LinkTemplate="{StaticResource LinkTemplate}" >
    </go:Diagram>

Sorry if I may have misled you.

The type of the Shape.StrokeDashArray property is DoubleCollection.

But the XHelper methods work with IEnumerable.

So your link data property either has to be of type DoubleCollection, or you need to use a Converter to convert the IEnumerable to a DoubleCollection.

Assuming you don’t want to use a converter in your Binding:

public DoubleCollection StrokeDashArray { get { return _StrokeDashArray; } set { if (_StrokeDashArray != value) { var old = _StrokeDashArray; _StrokeDashArray = value; RaisePropertyChanged("StrokeDashArray", old, value); } } } private DoubleCollection _StrokeDashArray = new DoubleCollection();
and your XML writing and reading code for that property would be like:

XHelper.Attribute("StrokeDashArray", linkdata.StrokeDashArray, new DoubleCollection())

and

linkdata.StrokeDashArray = new DoubleCollection(XHelper.Read("StrokeDashArray", e, new DoubleCollection()))

Actually it might be nice to allocate a single static empty DoubleCollection, so that you don’t re-allocate it on each call. But that’s just an optimization.

Perfect Walter, thank you!! Now, is reading from xml file!!

//The data class representing links.
public class MyLinkData : GraphLinksModelLinkData<String, String>
{

    public DoubleCollection StrokeDashArray
    {
        get { return _StrokeDashArray; }
        set
        {
            if (_StrokeDashArray != value)
            {
                var old = _StrokeDashArray;
                _StrokeDashArray = value;
                RaisePropertyChanged("StrokeDashArray", old, value);
            }
        }
    }
    private DoubleCollection _StrokeDashArray = new DoubleCollection() { };


    public override XElement MakeXElement(XName n)
    {
        XElement e = base.MakeXElement(n);
        e.Add(XHelper.Attribute("StrokeDashArray", this.StrokeDashArray, new DoubleCollection() {  }));

        return e;
    }

    public override void LoadFromXElement(XElement e)
    {
        base.LoadFromXElement(e);
        this.StrokeDashArray = new DoubleCollection(XHelper.Read("StrokeDashArray", e, new DoubleCollection() { }));
    }

    public MyLinkData()
    {
        this.Text = "Yes";
    }

}

Just one and final question:

I loaded StrokeDashArray data, but user can change some StrokeDashArray after load xml, because I created a method to set it, and after user can click in a button to save it :

private void LinkShape_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
((LinkShape)sender).StrokeDashArray = new DoubleCollection() { 2 };
}

private void Save_Click(object sender, RoutedEventArgs e)
{
var model = myDiagram.Model as GraphLinksModel<MyNodeData, String, String, MyLinkData>;
if (model == null)
{
return;
}

        XElement root = model.Save<MyNodeData, MyLinkData>("FlowChart", "MyNodeData", "MyLinkData");
        //Instead of using a file, just save the text to memory here
        WpfApplication1.MainWindow.Instance.SavedXML = root.ToString();
        LoadButton.IsEnabled = true;
        model.IsModified = false;  
    }

After user Save(), MakeXElement will be called from public class MyLinkData, but StrokeDashArray property will have the original values from xml…

Is there a way to Update StrokeDashArray from a specifc node of public class MyLinkData ?

You are modifying the Shape element instead of modifying the link data.
By doing so you are wiping out the data binding of the Shape.StrokeDashArray property.

Alternatively, you could change the Binding to be Mode=TwoWay.

Also, you should wrap changes to your model data (or to the model itself) within a transaction.

private void LinkShape_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { Link link = Part.FindAncestor<Link>(sender as UIElement); if (link == null) return; MyLinkData data = link.Data as MyLinkData; if (data == null) return; myDiagram.StartTransaction("Modify Link"); data.StrokeDashArray = new DoubleCollection() { 2 }; myDiagram.CommitTransaction("Modify Link"); }

Thank you very much!! Perfect!!