views:

388

answers:

2

I have a silverlight app that allows the user to draw on it and save the drawing.

The strokecollection in the canvas is converted to xml attributes and stored in the database.

the only problem i have now is converting the xml back into a stroke collection.

my strokes are stored as such:

<Strokes>    
  <Stroke>    
    <Color A="255" R="0" G="0" B="0" />      
    <OutlineColor A="0" R="0" G="0" B="0" />      
  <Points>
    <Point X="60" Y="57" PressureFactor="0.5" />        
    <Point X="332" Y="52" PressureFactor="0.5" />      
  </Points>      
  <Width>3</Width>      
  <Height>3</Height>    
  </Stroke>  
</Strokes>
A: 

Here is my solution... it appears I thought it was too confusing before I actually sat down and looked at it:

private StrokeCollection CreateStrokeCollectionfromXML(string XMLStrokes)
    {
        XElement xmlElem;
        try
        {
            xmlElem = XElement.Parse(XMLStrokes);
        }
        catch (XmlException ex)
        {
            return new StrokeCollection();
        }
        StrokeCollection objStrokes = new StrokeCollection();
        //Query the XML to extract the Strokes
        var strokes = from s in xmlElem.Descendants("Stroke") select s;
        foreach (XElement strokeNodeElement in strokes)
        {
            var color = (from c in strokeNodeElement.Descendants("Color")
                        select c).FirstOrDefault();
            DrawingAttributes attributes = new DrawingAttributes();

            byte colorA = Convert.ToByte(color.Attribute("A").Value);
            byte colorR = Convert.ToByte(color.Attribute("R").Value);
            byte colorG = Convert.ToByte(color.Attribute("G").Value);
            byte colorB = Convert.ToByte(color.Attribute("B").Value);

            attributes.Color = Color.FromArgb(colorA, colorR, colorG, colorB);

            var outlineColor = (from oc in strokeNodeElement.Descendants("OutlineColor")
                                select oc).FirstOrDefault();

            byte outlineColorA = Convert.ToByte(outlineColor.Attribute("A").Value);
            byte outlineColorR = Convert.ToByte(outlineColor.Attribute("R").Value);
            byte outlineColorG = Convert.ToByte(outlineColor.Attribute("G").Value);
            byte outlineColorB = Convert.ToByte(outlineColor.Attribute("B").Value);

            attributes.OutlineColor = Color.FromArgb(outlineColorA, outlineColorR, outlineColorG, outlineColorB);

            attributes.Width = Convert.ToInt32(strokeNodeElement.Descendants("Width").FirstOrDefault().Value);
            attributes.Height = Convert.ToInt32(strokeNodeElement.Descendants("Height").FirstOrDefault().Value);

            var points = from p in strokeNodeElement.Descendants("Point")
                         select p;
            StylusPointCollection pointData = new System.Windows.Input.StylusPointCollection();

            foreach (XElement point in points)
            {
                double Xvalue = Convert.ToDouble(point.Attribute("X").Value);
                double Yvalue = Convert.ToDouble(point.Attribute("Y").Value);
                pointData.Add(new StylusPoint(Xvalue, Yvalue));
            }

            Stroke newstroke = new Stroke();
            newstroke.DrawingAttributes = attributes;
            newstroke.StylusPoints.Add(pointData);
            //add the new stroke to the StrokeCollection
            objStrokes.Add(newstroke);
        }
        return objStrokes;
    }
Jimmy
Its a good starter for 10. However, I think it would be safe to assume that Stroke elements don't themselves contain stroke elements. Hence use Elements instead of Descendants.
AnthonyWJones
Factor into a function the creation of a Color from an element.
AnthonyWJones
Why not simply use `var color = strokeNodeElement.Element("Color")` instead of all that unnecessary LINQ stuff.
AnthonyWJones
Combining those last two comments eliminates 10 lines of code from the main for loop.
AnthonyWJones
In fact all usage of `from` is superflous here.
AnthonyWJones
Another factoring creating a `StylusPointFromElement` would help the structure of the inner loop, reducing it to a single line.
AnthonyWJones
care to show some examples of what you mean? i'm new to silverlight stuff so don't quite get what you're getting at
Jimmy
and your first point is sort of invalid because in a larger version there are multiple stroke elements within the strokes collection
Jimmy
@Jimmy: I can see there would be multiple Stroke elements in the root Strokes element, however, there won't be Stroke elements buried further down inside an outer Stroke element. Use Descendants where you want to find an element at any level of heirarchy but Elements is faster when you know the element name is only found as direct children of a parent node.
AnthonyWJones
A: 

Here is your code heavily factored:-

private StrokeCollection CreateStrokeCollection(string XMLStrokes)
{
  XElement xmlElem;
  try
  {
    return CreateStrokeCollect(XElement.Parse(XMLStrokes).Root);
  }
  catch (XmlException ex)
  {
    return new StrokeCollection();
  }
}

private StrokeCollection CreateStrokeCollection(XElement elem)
{  
  StrokeCollection result= new StrokeCollection();
  foreach (XElement elem in xmlElement.Elements("Stroke"))
  {
     result.Add(CreateStroke(elem));
  }
  return result;
}


private Stroke CreateStroke(XElement elem)
{
  var result = new Stroke();
  result.DrawingAttributes = CreateAttributes(elem);
  result.StylusPoints.Add(CreatePointCollection(elem.Element("Points"));
  return result;
}

private StylusPointCollection CreatePointCollection(XElement elem)
{
  var result = new StylusPointCollection();
  foreach (XElment pointElem in elem.Elements("Point"))
  {
    result.Add(CreateStylusPoint(pointElem));
  }
  return result;
}

private StylusPoint CreateStylusPoint(XElement elem)
{
    double x = Convert.ToDouble(point.Attribute("X").Value);
    double y = Convert.ToDouble(point.Attribute("Y").Value);
    return new StylusPoint(x, y);
}

private DrawingAttributes CreateAttributes(XElement elem)
{
   var result = new DrawingAttributes();
   result.Color = CreateColor(elem.Element("Color"));
   result.OutlineColor = CreateColor(elem.Element("OutlineColor"));
   result.Width = Convert.ToInt32(elem.Element("Width").Value);
   result.Height = Convert.ToInt32(elem.Element("Height").Value);
   return result ;
}

private Color CreateColor(XElement elem)
{
  byte colorA = Convert.ToByte(color.Attribute("A").Value);
  byte colorR = Convert.ToByte(color.Attribute("R").Value);
  byte colorG = Convert.ToByte(color.Attribute("G").Value);
  byte colorB = Convert.ToByte(color.Attribute("B").Value);

  return Color.FromArgb(colorA, colorR, colorG, colorB);       
}
AnthonyWJones