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 = 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/m

112                         _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                         do

144                         {

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 Bezier

169                         EnsureFigure();

170 

171                         do

172                         {

173                             Point p;

174 

175                             if ((cmd == 's') || (cmd == 'S'))

176                             {

177                                 if (last_cmd == 'C')

178                                 {

179                                     p = Reflect();

180                                 }

181                                 else

182                                 {

183                                     p = _lastPoint;

184                                 }

185 

186                                 _secondLastPoint = ReadPoint(cmd, !AllowComma);

187                             }

188                             else

189                             {

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 Bezier

214                         EnsureFigure();

215 

216                         do

217                         {

218                             if ((cmd == 't') || (cmd == 'T'))

219                             {

220                                 if (last_cmd == 'Q')

221                                 {

222                                     _secondLastPoint = Reflect();

223                                 }

224                                 else

225                                 {

226                                     _secondLastPoint = _lastPoint;

227                                 }

228 

229                                 _lastPoint = ReadPoint(cmd, !AllowComma);

230                             }

231                             else

232                             {

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                         do

254                         {

255                             // A 3,4 5, 0, 0, 6,7

256                             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                             //    !IsSmoothJoin

279                             //    );

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 figure

296                         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 sign

399             //

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 characters

416                 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 will

423                 // do this for us later. 

424                 //

425                 _curIndex = Math.Min(_curIndex + 3, _pathLength); // "NaN" has 3 characters

426                 simple = false;

427             }

428             else

429             {

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                 // Exponent

441                 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 integer

450             {

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 = 0;

464 

465                 while (start < _curIndex)

466                 {

467                     value = value * 10 + (_pathString[start] - '0');

468                     start++;

469                 }

470 

471                 return value * sign;

472             }

473             else

474             {

475                 string subString = _pathString.Substring(start, _curIndex - start);

476 

477                 try

478                 {

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 number

497                 if ((_token == '.') || (_token == '-') || (_token == '+') || ((_token >= '0') && (_token <= '9'))

498                     || (_token == 'I')  // Infinity

499                     || (_token == 'N')) // NaN 

500                 {

501                     return true;

502                 }

503             }

504 

505             if (commaMet) // Only allowed between numbers

506             {

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 relative

519             {

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             else

539             {

540                 return false;

541             }

542         }

543 

544         bool More()

545         {

546             return _curIndex < _pathLength;

547         }

548 

549         // Skip white space, one comma if allowed

550         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 only

571                         }

572                         else

573                         {

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 possible

603             // 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.Point3

649                              ));

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         #endregion

683 

684         #region IValueConverter Members

685 

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             else

692                 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             else

702                 return default(string);

703         }

704 

705         #endregion

706     }
View Code

 

你可能感兴趣的:(silverlight)