首页 > 代码库 > 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 }
Silverlight日记:字符串装换成Path对象
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。