首页 > 代码库 > Silverlight日记:字符串装换成Path对象

Silverlight日记:字符串装换成Path对象

一,需要动态绑定Path

 1 <UserControl x:Class="Secom.Emx2.SL.Common.Controls.EleSafe.Ele.Line" 2     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6     mc:Ignorable="d" 7     d:DesignHeight="300" d:DesignWidth="400"> 8  9     <Path x:Name="myline" Stretch="Fill" Width="{Binding Width, ElementName=path, Mode=TwoWay}" Height="{Binding Height, ElementName=path, Mode=TwoWay}"/>10 </UserControl>

二,生成Path

 1  private LineType _lineType = LineType.VLine; 2         public LineType LineType 3         { 4             get 5             { 6                 return _lineType; 7             } 8             set 9             {10                 _lineType = value;11                 var pathString = string.Empty;12                 var eff = new DropShadowEffect();13                 eff.BlurRadius = 5;14                 eff.Color = Colors.DarkGray;15                 eff.ShadowDepth = 0;16                 var conv = new StringToPathGeometryConverter();17                 switch (_lineType)18                 {19                     case LineType.HLine:20                         eff.Direction = 0;21                         pathString = "M0,0 L131.137,0";22                         break;23                     case LineType.VLine:24                     default:25                         eff.Direction = 90;26                         pathString = "M87,60 L87,240.178";27                         break;28                 }29 30                 var pathData =http://www.mamicode.com/ conv.Convert(pathString);31                 myline.SetValue(Path.DataProperty, pathData);32                 //myline.SetValue(Path.EffectProperty, eff);33             }34         }

三,字符串转换成Path对象类

  1     /* ==============================  2      * Desc:StringToPathGeometry    3      * Author:hezp  4      * Date:2014/8/9 17:39:40  5      * ==============================*/  6     public class StringToPathGeometryConverter : IValueConverter  7     {  8         #region Const & Private Variables  9         const bool AllowSign = true; 10         const bool AllowComma = true; 11         const bool IsFilled = true; 12         const bool IsClosed = true; 13  14         IFormatProvider _formatProvider; 15  16         PathFigure _figure = null;     // Figure object, which will accept parsed segments 17         string _pathString;        // Input string to be parsed 18         int _pathLength; 19         int _curIndex;          // Location to read next character from 20         bool _figureStarted;     // StartFigure is effective  21  22         Point _lastStart;         // Last figure starting point 23         Point _lastPoint;         // Last point  24         Point _secondLastPoint;   // The point before last point 25  26         char _token;             // Non whitespace character returned by ReadToken 27         #endregion 28  29         #region Public Functionality 30         /// <summary> 31         /// Main conversion routine - converts string path data definition to PathGeometry object 32         /// </summary> 33         /// <param name="path">String with path data definition</param> 34         /// <returns>PathGeometry object created from string definition</returns> 35         public PathGeometry Convert(string path) 36         { 37             if (null == path) 38                 throw new ArgumentException("Path string cannot be null!"); 39  40             if (path.Length == 0) 41                 throw new ArgumentException("Path string cannot be empty!"); 42  43             return parse(path); 44         } 45  46         /// <summary> 47         /// Main back conversion routine - converts PathGeometry object to its string equivalent 48         /// </summary> 49         /// <param name="geometry">Path Geometry object</param> 50         /// <returns>String equivalent to PathGeometry contents</returns> 51         public string ConvertBack(PathGeometry geometry) 52         { 53             if (null == geometry) 54                 throw new ArgumentException("Path Geometry cannot be null!"); 55  56             return parseBack(geometry); 57         } 58         #endregion 59  60         #region Private Functionality 61         /// <summary> 62         /// Main parser routine, which loops over each char in received string, and performs actions according to command/parameter being passed 63         /// </summary> 64         /// <param name="path">String with path data definition</param> 65         /// <returns>PathGeometry object created from string definition</returns> 66         private PathGeometry parse(string path) 67         { 68             PathGeometry _pathGeometry = null; 69  70  71             _formatProvider = CultureInfo.InvariantCulture; 72             _pathString = path; 73             _pathLength = path.Length; 74             _curIndex = 0; 75  76             _secondLastPoint = new Point(0, 0); 77             _lastPoint = new Point(0, 0); 78             _lastStart = new Point(0, 0); 79  80             _figureStarted = false; 81  82             bool first = true; 83  84             char last_cmd =  ; 85  86             while (ReadToken()) // Empty path is allowed in XAML 87             { 88                 char cmd = _token; 89  90                 if (first) 91                 { 92                     if ((cmd != M) && (cmd != m) && (cmd != f) && (cmd != F))  // Path starts with M|m  93                     { 94                         ThrowBadToken(); 95                     } 96  97                     first = false; 98                 } 99 100                 switch (cmd)101                 {102                     case f:103                     case F:104                         _pathGeometry = new PathGeometry();105                         double _num = ReadNumber(!AllowComma);106                         _pathGeometry.FillRule = _num == 0 ? FillRule.EvenOdd : FillRule.Nonzero;107                         break;108 109                     case m:110                     case M:111                         // XAML allows multiple points after M/m112                         _lastPoint = ReadPoint(cmd, !AllowComma);113 114                         _figure = new PathFigure();115                         _figure.StartPoint = _lastPoint;116                         _figure.IsFilled = IsFilled;117                         _figure.IsClosed = !IsClosed;118                         //context.BeginFigure(_lastPoint, IsFilled, !IsClosed);119                         _figureStarted = true;120                         _lastStart = _lastPoint;121                         last_cmd = M;122 123                         while (IsNumber(AllowComma))124                         {125                             _lastPoint = ReadPoint(cmd, !AllowComma);126 127                             LineSegment _lineSegment = new LineSegment();128                             _lineSegment.Point = _lastPoint;129                             _figure.Segments.Add(_lineSegment);130                             //context.LineTo(_lastPoint, IsStroked, !IsSmoothJoin);131                             last_cmd = L;132                         }133                         break;134 135                     case l:136                     case L:137                     case h:138                     case H:139                     case v:140                     case V:141                         EnsureFigure();142 143                         do144                         {145                             switch (cmd)146                             {147                                 case l: _lastPoint = ReadPoint(cmd, !AllowComma); break;148                                 case L: _lastPoint = ReadPoint(cmd, !AllowComma); break;149                                 case h: _lastPoint.X += ReadNumber(!AllowComma); break;150                                 case H: _lastPoint.X = ReadNumber(!AllowComma); break;151                                 case v: _lastPoint.Y += ReadNumber(!AllowComma); break;152                                 case V: _lastPoint.Y = ReadNumber(!AllowComma); break;153                             }154 155                             LineSegment _lineSegment = new LineSegment();156                             _lineSegment.Point = _lastPoint;157                             _figure.Segments.Add(_lineSegment);158                             //context.LineTo(_lastPoint, IsStroked, !IsSmoothJoin);159                         }160                         while (IsNumber(AllowComma));161 162                         last_cmd = L;163                         break;164 165                     case c:166                     case C: // cubic Bezier 167                     case s:168                     case S: // smooth cublic Bezier169                         EnsureFigure();170 171                         do172                         {173                             Point p;174 175                             if ((cmd == s) || (cmd == S))176                             {177                                 if (last_cmd == C)178                                 {179                                     p = Reflect();180                                 }181                                 else182                                 {183                                     p = _lastPoint;184                                 }185 186                                 _secondLastPoint = ReadPoint(cmd, !AllowComma);187                             }188                             else189                             {190                                 p = ReadPoint(cmd, !AllowComma);191 192                                 _secondLastPoint = ReadPoint(cmd, AllowComma);193                             }194 195                             _lastPoint = ReadPoint(cmd, AllowComma);196 197                             BezierSegment _bizierSegment = new BezierSegment();198                             _bizierSegment.Point1 = p;199                             _bizierSegment.Point2 = _secondLastPoint;200                             _bizierSegment.Point3 = _lastPoint;201                             _figure.Segments.Add(_bizierSegment);202                             //context.BezierTo(p, _secondLastPoint, _lastPoint, IsStroked, !IsSmoothJoin);203 204                             last_cmd = C;205                         }206                         while (IsNumber(AllowComma));207 208                         break;209 210                     case q:211                     case Q: // quadratic Bezier 212                     case t:213                     case T: // smooth quadratic Bezier214                         EnsureFigure();215 216                         do217                         {218                             if ((cmd == t) || (cmd == T))219                             {220                                 if (last_cmd == Q)221                                 {222                                     _secondLastPoint = Reflect();223                                 }224                                 else225                                 {226                                     _secondLastPoint = _lastPoint;227                                 }228 229                                 _lastPoint = ReadPoint(cmd, !AllowComma);230                             }231                             else232                             {233                                 _secondLastPoint = ReadPoint(cmd, !AllowComma);234                                 _lastPoint = ReadPoint(cmd, AllowComma);235                             }236 237                             QuadraticBezierSegment _quadraticBezierSegment = new QuadraticBezierSegment();238                             _quadraticBezierSegment.Point1 = _secondLastPoint;239                             _quadraticBezierSegment.Point2 = _lastPoint;240                             _figure.Segments.Add(_quadraticBezierSegment);241                             //context.QuadraticBezierTo(_secondLastPoint, _lastPoint, IsStroked, !IsSmoothJoin);242 243                             last_cmd = Q;244                         }245                         while (IsNumber(AllowComma));246 247                         break;248 249                     case a:250                     case A:251                         EnsureFigure();252 253                         do254                         {255                             // A 3,4 5, 0, 0, 6,7256                             double w = ReadNumber(!AllowComma);257                             double h = ReadNumber(AllowComma);258                             double rotation = ReadNumber(AllowComma);259                             bool large = ReadBool();260                             bool sweep = ReadBool();261 262                             _lastPoint = ReadPoint(cmd, AllowComma);263 264                             ArcSegment _arcSegment = new ArcSegment();265                             _arcSegment.Point = _lastPoint;266                             _arcSegment.Size = new Size(w, h);267                             _arcSegment.RotationAngle = rotation;268                             _arcSegment.IsLargeArc = large;269                             _arcSegment.SweepDirection = sweep ? SweepDirection.Clockwise : SweepDirection.Counterclockwise;270                             _figure.Segments.Add(_arcSegment);271                             //context.ArcTo(272                             //    _lastPoint,273                             //    new Size(w, h),274                             //    rotation,275                             //    large,276                             //    sweep ? SweepDirection.Clockwise : SweepDirection.Counterclockwise,277                             //    IsStroked,278                             //    !IsSmoothJoin279                             //    );280                         }281                         while (IsNumber(AllowComma));282 283                         last_cmd = A;284                         break;285 286                     case z:287                     case Z:288                         EnsureFigure();289                         _figure.IsClosed = IsClosed;290                         //context.SetClosedState(IsClosed);291 292                         _figureStarted = false;293                         last_cmd = Z;294 295                         _lastPoint = _lastStart; // Set reference point to be first point of current figure296                         break;297 298                     default:299                         ThrowBadToken();300                         break;301                 }302 303                 if (null != _figure)304                 {305                     if (_figure.IsClosed)306                     {307                         if (null == _pathGeometry)308                             _pathGeometry = new PathGeometry();309 310                         _pathGeometry.Figures.Add(_figure);311 312                         _figure = null;313                         first = true;314                     }315                 }316 317 318             }319 320             if (null != _figure)321             {322                 if (null == _pathGeometry)323                     _pathGeometry = new PathGeometry();324 325                 if (!_pathGeometry.Figures.Contains(_figure))326                     _pathGeometry.Figures.Add(_figure);327 328             }329             return _pathGeometry;330         }331 332         void SkipDigits(bool signAllowed)333         {334             // Allow for a sign 335             if (signAllowed && More() && ((_pathString[_curIndex] == -) || _pathString[_curIndex] == +))336             {337                 _curIndex++;338             }339 340             while (More() && (_pathString[_curIndex] >= 0) && (_pathString[_curIndex] <= 9))341             {342                 _curIndex++;343             }344         }345 346         bool ReadBool()347         {348             SkipWhiteSpace(AllowComma);349 350             if (More())351             {352                 _token = _pathString[_curIndex++];353 354                 if (_token == 0)355                 {356                     return false;357                 }358                 else if (_token == 1)359                 {360                     return true;361                 }362             }363 364             ThrowBadToken();365 366             return false;367         }368 369         private Point Reflect()370         {371             return new Point(2 * _lastPoint.X - _secondLastPoint.X,372                              2 * _lastPoint.Y - _secondLastPoint.Y);373         }374 375         private void EnsureFigure()376         {377             if (!_figureStarted)378             {379                 _figure = new PathFigure();380                 _figure.StartPoint = _lastStart;381 382                 //_context.BeginFigure(_lastStart, IsFilled, !IsClosed);383                 _figureStarted = true;384             }385         }386 387         double ReadNumber(bool allowComma)388         {389             if (!IsNumber(allowComma))390             {391                 ThrowBadToken();392             }393 394             bool simple = true;395             int start = _curIndex;396 397             //398             // Allow for a sign399             //400             // There are numbers that cannot be preceded with a sign, for instance, -NaN, but it‘s 401             // fine to ignore that at this point, since the CLR parser will catch this later.402             // 403             if (More() && ((_pathString[_curIndex] == -) || _pathString[_curIndex] == +))404             {405                 _curIndex++;406             }407 408             // Check for Infinity (or -Infinity).409             if (More() && (_pathString[_curIndex] == I))410             {411                 // 412                 // Don‘t bother reading the characters, as the CLR parser will 413                 // do this for us later.414                 // 415                 _curIndex = Math.Min(_curIndex + 8, _pathLength); // "Infinity" has 8 characters416                 simple = false;417             }418             // Check for NaN 419             else if (More() && (_pathString[_curIndex] == N))420             {421                 // 422                 // Don‘t bother reading the characters, as the CLR parser will423                 // do this for us later. 424                 //425                 _curIndex = Math.Min(_curIndex + 3, _pathLength); // "NaN" has 3 characters426                 simple = false;427             }428             else429             {430                 SkipDigits(!AllowSign);431 432                 // Optional period, followed by more digits 433                 if (More() && (_pathString[_curIndex] == .))434                 {435                     simple = false;436                     _curIndex++;437                     SkipDigits(!AllowSign);438                 }439 440                 // Exponent441                 if (More() && ((_pathString[_curIndex] == E) || (_pathString[_curIndex] == e)))442                 {443                     simple = false;444                     _curIndex++;445                     SkipDigits(AllowSign);446                 }447             }448 449             if (simple && (_curIndex <= (start + 8))) // 32-bit integer450             {451                 int sign = 1;452 453                 if (_pathString[start] == +)454                 {455                     start++;456                 }457                 else if (_pathString[start] == -)458                 {459                     start++;460                     sign = -1;461                 }462 463                 int value = http://www.mamicode.com/0;464 465                 while (start < _curIndex)466                 {467                     value = http://www.mamicode.com/value * 10 + (_pathString[start] - 0);468                     start++;469                 }470 471                 return value * sign;472             }473             else474             {475                 string subString = _pathString.Substring(start, _curIndex - start);476 477                 try478                 {479                     return System.Convert.ToDouble(subString, _formatProvider);480                 }481                 catch (FormatException except)482                 {483                     throw new FormatException(string.Format("Unexpected character in path ‘{0}‘ at position {1}", _pathString, _curIndex - 1), except);484                 }485             }486         }487 488         private bool IsNumber(bool allowComma)489         {490             bool commaMet = SkipWhiteSpace(allowComma);491 492             if (More())493             {494                 _token = _pathString[_curIndex];495 496                 // Valid start of a number497                 if ((_token == .) || (_token == -) || (_token == +) || ((_token >= 0) && (_token <= 9))498                     || (_token == I)  // Infinity499                     || (_token == N)) // NaN 500                 {501                     return true;502                 }503             }504 505             if (commaMet) // Only allowed between numbers506             {507                 ThrowBadToken();508             }509 510             return false;511         }512 513         private Point ReadPoint(char cmd, bool allowcomma)514         {515             double x = ReadNumber(allowcomma);516             double y = ReadNumber(AllowComma);517 518             if (cmd >= a) // ‘A‘ < ‘a‘. lower case for relative519             {520                 x += _lastPoint.X;521                 y += _lastPoint.Y;522             }523 524             return new Point(x, y);525         }526 527         private bool ReadToken()528         {529             SkipWhiteSpace(!AllowComma);530 531             // Check for end of string 532             if (More())533             {534                 _token = _pathString[_curIndex++];535 536                 return true;537             }538             else539             {540                 return false;541             }542         }543 544         bool More()545         {546             return _curIndex < _pathLength;547         }548 549         // Skip white space, one comma if allowed550         private bool SkipWhiteSpace(bool allowComma)551         {552             bool commaMet = false;553 554             while (More())555             {556                 char ch = _pathString[_curIndex];557 558                 switch (ch)559                 {560                     case  :561                     case \n:562                     case \r:563                     case \t: // SVG whitespace 564                         break;565 566                     case ,:567                         if (allowComma)568                         {569                             commaMet = true;570                             allowComma = false; // one comma only571                         }572                         else573                         {574                             ThrowBadToken();575                         }576                         break;577 578                     default:579                         // Avoid calling IsWhiteSpace for ch in (‘ ‘ .. ‘z‘]580                         if (((ch >  ) && (ch <= z)) || !Char.IsWhiteSpace(ch))581                         {582                             return commaMet;583                         }584                         break;585                 }586 587                 _curIndex++;588             }589 590             return commaMet;591         }592 593         private void ThrowBadToken()594         {595             throw new FormatException(string.Format("Unexpected character in path ‘{0}‘ at position {1}", _pathString, _curIndex - 1));596         }597 598         static internal char GetNumericListSeparator(IFormatProvider provider)599         {600             char numericSeparator = ,;601 602             // Get the NumberFormatInfo out of the provider, if possible603             // If the IFormatProvider doesn‘t not contain a NumberFormatInfo, then 604             // this method returns the current culture‘s NumberFormatInfo. 605             NumberFormatInfo numberFormat = NumberFormatInfo.GetInstance(provider);606 607             // Is the decimal separator is the same as the list separator?608             // If so, we use the ";". 609             if ((numberFormat.NumberDecimalSeparator.Length > 0) && (numericSeparator == numberFormat.NumberDecimalSeparator[0]))610             {611                 numericSeparator = ;;612             }613 614             return numericSeparator;615         }616 617         private string parseBack(PathGeometry geometry)618         {619             System.Text.StringBuilder sb = new System.Text.StringBuilder();620             IFormatProvider provider = new System.Globalization.CultureInfo("en-us");621             string format = null;622 623             sb.Append("F" + (geometry.FillRule == FillRule.EvenOdd ? "0" : "1") + " ");624 625             foreach (PathFigure figure in geometry.Figures)626             {627                 sb.Append("M " + ((IFormattable)figure.StartPoint).ToString(format, provider) + " ");628 629                 foreach (PathSegment segment in figure.Segments)630                 {631                     char separator = GetNumericListSeparator(provider);632 633                     if (segment.GetType() == typeof(LineSegment))634                     {635                         LineSegment _lineSegment = segment as LineSegment;636 637                         sb.Append("L " + ((IFormattable)_lineSegment.Point).ToString(format, provider) + " ");638                     }639                     else if (segment.GetType() == typeof(BezierSegment))640                     {641                         BezierSegment _bezierSegment = segment as BezierSegment;642 643                         sb.Append(String.Format(provider,644                              "C{1:" + format + "}{0}{2:" + format + "}{0}{3:" + format + "} ",645                              separator,646                              _bezierSegment.Point1,647                              _bezierSegment.Point2,648                              _bezierSegment.Point3649                              ));650                     }651                     else if (segment.GetType() == typeof(QuadraticBezierSegment))652                     {653                         QuadraticBezierSegment _quadraticBezierSegment = segment as QuadraticBezierSegment;654 655                         sb.Append(String.Format(provider,656                              "Q{1:" + format + "}{0}{2:" + format + "} ",657                              separator,658                              _quadraticBezierSegment.Point1,659                              _quadraticBezierSegment.Point2));660                     }661                     else if (segment.GetType() == typeof(ArcSegment))662                     {663                         ArcSegment _arcSegment = segment as ArcSegment;664 665                         sb.Append(String.Format(provider,666                              "A{1:" + format + "}{0}{2:" + format + "}{0}{3}{0}{4}{0}{5:" + format + "} ",667                              separator,668                              _arcSegment.Size,669                              _arcSegment.RotationAngle,670                              _arcSegment.IsLargeArc ? "1" : "0",671                              _arcSegment.SweepDirection == SweepDirection.Clockwise ? "1" : "0",672                              _arcSegment.Point));673                     }674                 }675 676                 if (figure.IsClosed)677                     sb.Append("Z");678             }679 680             return sb.ToString();681         }682         #endregion683 684         #region IValueConverter Members685 686         public object Convert(object value, Type targetType, object parameter, CultureInfo culture)687         {688             string path = value as string;689             if (null != path)690                 return Convert(path);691             else692                 return null;693         }694 695         public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)696         {697             PathGeometry geometry = value as PathGeometry;698 699             if (null != geometry)700                 return ConvertBack(geometry);701             else702                 return default(string);703         }704 705         #endregion706     }
View Code

 

Silverlight日记:字符串装换成Path对象