AngleBorder.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  1. using CustomUI.Utils;
  2. using System;
  3. using System.Runtime.InteropServices;
  4. using System.Windows;
  5. using System.Windows.Controls;
  6. using System.Windows.Media;
  7. namespace CustomUI
  8. {
  9. /// <summary>
  10. /// 带三角形的气泡边框
  11. /// </summary>
  12. public class AngleBorder : Decorator
  13. {
  14. #region 依赖属性
  15. public static readonly DependencyProperty PlacementProperty =
  16. DependencyProperty.Register("Placement", typeof(EnumPlacement), typeof(AngleBorder),
  17. new FrameworkPropertyMetadata(EnumPlacement.RightCenter, FrameworkPropertyMetadataOptions.AffectsRender, OnDirectionPropertyChangedCallback));
  18. public EnumPlacement Placement
  19. {
  20. get { return (EnumPlacement)GetValue(PlacementProperty); }
  21. set { SetValue(PlacementProperty, value); }
  22. }
  23. public static readonly DependencyProperty TailWidthProperty =
  24. DependencyProperty.Register("TailWidth", typeof(double), typeof(AngleBorder), new PropertyMetadata(10d));
  25. /// <summary>
  26. /// 尾巴的宽度,默认值为7
  27. /// </summary>
  28. public double TailWidth
  29. {
  30. get { return (double)GetValue(TailWidthProperty); }
  31. set { SetValue(TailWidthProperty, value); }
  32. }
  33. public static readonly DependencyProperty TailHeightProperty =
  34. DependencyProperty.Register("TailHeight", typeof(double), typeof(AngleBorder), new PropertyMetadata(10d));
  35. /// <summary>
  36. /// 尾巴的高度,默认值为10
  37. /// </summary>
  38. public double TailHeight
  39. {
  40. get { return (double)GetValue(TailHeightProperty); }
  41. set { SetValue(TailHeightProperty, value); }
  42. }
  43. public static readonly DependencyProperty TailVerticalOffsetProperty =
  44. DependencyProperty.Register("TailVerticalOffset", typeof(double), typeof(AngleBorder), new PropertyMetadata(13d));
  45. /// <summary>
  46. /// 尾巴距离顶部的距离,默认值为10
  47. /// </summary>
  48. public double TailVerticalOffset
  49. {
  50. get { return (double)GetValue(TailVerticalOffsetProperty); }
  51. set { SetValue(TailVerticalOffsetProperty, value); }
  52. }
  53. public static readonly DependencyProperty TailHorizontalOffsetProperty =
  54. DependencyProperty.Register("TailHorizontalOffset", typeof(double), typeof(AngleBorder),
  55. new PropertyMetadata(12d));
  56. /// <summary>
  57. /// 尾巴距离顶部的距离,默认值为10
  58. /// </summary>
  59. public double TailHorizontalOffset
  60. {
  61. get { return (double)GetValue(TailHorizontalOffsetProperty); }
  62. set { SetValue(TailHorizontalOffsetProperty, value); }
  63. }
  64. public static readonly DependencyProperty BackgroundProperty =
  65. DependencyProperty.Register("Background", typeof(Brush), typeof(AngleBorder)
  66. , new PropertyMetadata(new SolidColorBrush(Color.FromRgb(255, 255, 255))));
  67. /// <summary>
  68. /// 背景色,默认值为#FFFFFF,白色
  69. /// </summary>
  70. public Brush Background
  71. {
  72. get { return (Brush)GetValue(BackgroundProperty); }
  73. set { SetValue(BackgroundProperty, value); }
  74. }
  75. public static readonly DependencyProperty PaddingProperty =
  76. DependencyProperty.Register("Padding", typeof(Thickness), typeof(AngleBorder)
  77. , new PropertyMetadata(new Thickness(10, 5, 10, 5)));
  78. /// <summary>
  79. /// 内边距
  80. /// </summary>
  81. public Thickness Padding
  82. {
  83. get { return (Thickness)GetValue(PaddingProperty); }
  84. set { SetValue(PaddingProperty, value); }
  85. }
  86. public static readonly DependencyProperty BorderBrushProperty =
  87. DependencyProperty.Register("BorderBrush", typeof(Brush), typeof(AngleBorder)
  88. , new PropertyMetadata(default(Brush)));
  89. /// <summary>
  90. /// 边框颜色
  91. /// </summary>
  92. public Brush BorderBrush
  93. {
  94. get { return (Brush)GetValue(BorderBrushProperty); }
  95. set { SetValue(BorderBrushProperty, value); }
  96. }
  97. public static readonly DependencyProperty BorderThicknessProperty =
  98. DependencyProperty.Register("BorderThickness", typeof(Thickness), typeof(AngleBorder), new PropertyMetadata(new Thickness(1d)));
  99. /// <summary>
  100. /// 边框大小
  101. /// </summary>
  102. public Thickness BorderThickness
  103. {
  104. get { return (Thickness)GetValue(BorderThicknessProperty); }
  105. set { SetValue(BorderThicknessProperty, value); }
  106. }
  107. public static readonly DependencyProperty CornerRadiusProperty =
  108. DependencyProperty.Register("CornerRadius", typeof(System.Windows.CornerRadius)
  109. , typeof(AngleBorder), new PropertyMetadata(new CornerRadius(0)));
  110. /// <summary>
  111. /// 边框大小
  112. /// </summary>
  113. public System.Windows.CornerRadius CornerRadius
  114. {
  115. get { return (System.Windows.CornerRadius)GetValue(CornerRadiusProperty); }
  116. set { SetValue(CornerRadiusProperty, value); }
  117. }
  118. #endregion
  119. #region 方法重写
  120. /// <summary>
  121. /// 该方法用于测量整个控件的大小
  122. /// </summary>
  123. /// <param name="constraint"></param>
  124. /// <returns>控件的大小</returns>
  125. protected override Size MeasureOverride(Size constraint)
  126. {
  127. Thickness padding = this.Padding;
  128. Size result = new Size();
  129. if (Child != null)
  130. {
  131. //测量子控件的大小
  132. Child.Measure(constraint);
  133. //三角形在左边与右边的,整个容器的宽度则为:里面子控件的宽度 + 设置的padding + 三角形的宽度
  134. //三角形在上面与下面的,整个容器的高度则为:里面子控件的高度 + 设置的padding + 三角形的高度
  135. switch (Placement)
  136. {
  137. case EnumPlacement.LeftTop:
  138. case EnumPlacement.LeftBottom:
  139. case EnumPlacement.LeftCenter:
  140. case EnumPlacement.RightTop:
  141. case EnumPlacement.RightBottom:
  142. case EnumPlacement.RightCenter:
  143. result.Width = Child.DesiredSize.Width + padding.Left + padding.Right + this.TailWidth;
  144. result.Height = Child.DesiredSize.Height + padding.Top + padding.Bottom;
  145. break;
  146. case EnumPlacement.TopLeft:
  147. case EnumPlacement.TopCenter:
  148. case EnumPlacement.TopRight:
  149. case EnumPlacement.BottomLeft:
  150. case EnumPlacement.BottomCenter:
  151. case EnumPlacement.BottomRight:
  152. result.Width = Child.DesiredSize.Width + padding.Left + padding.Right;
  153. result.Height = Child.DesiredSize.Height + padding.Top + padding.Bottom + this.TailHeight;
  154. break;
  155. default:
  156. break;
  157. }
  158. }
  159. return result;
  160. }
  161. /// <summary>
  162. /// 设置子控件的大小与位置
  163. /// </summary>
  164. /// <param name="arrangeSize"></param>
  165. /// <returns></returns>
  166. protected override Size ArrangeOverride(Size arrangeSize)
  167. {
  168. Thickness padding = this.Padding;
  169. if (Child != null)
  170. {
  171. switch (Placement)
  172. {
  173. case EnumPlacement.LeftTop:
  174. case EnumPlacement.LeftBottom:
  175. case EnumPlacement.LeftCenter:
  176. this.TailWidth = 6;
  177. Child.Arrange(new Rect(new Point(padding.Left + this.TailWidth, padding.Top), Child.DesiredSize));
  178. //ArrangeChildLeft();
  179. break;
  180. case EnumPlacement.RightTop:
  181. case EnumPlacement.RightBottom:
  182. case EnumPlacement.RightCenter:
  183. ArrangeChildRight(padding);
  184. break;
  185. case EnumPlacement.TopLeft:
  186. case EnumPlacement.TopRight:
  187. case EnumPlacement.TopCenter:
  188. Child.Arrange(new Rect(new Point(padding.Left, this.TailHeight + padding.Top), Child.DesiredSize));
  189. break;
  190. case EnumPlacement.BottomLeft:
  191. case EnumPlacement.BottomRight:
  192. case EnumPlacement.BottomCenter:
  193. Child.Arrange(new Rect(new Point(padding.Left, padding.Top), Child.DesiredSize));
  194. break;
  195. default:
  196. break;
  197. }
  198. }
  199. return arrangeSize;
  200. }
  201. private void ArrangeChildRight(Thickness padding)
  202. {
  203. double x = padding.Left;
  204. double y = padding.Top;
  205. if (!Double.IsNaN(this.Height) && this.Height != 0)
  206. {
  207. y = (this.Height - (Child.DesiredSize.Height)) / 2;
  208. }
  209. Child.Arrange(new Rect(new Point(x, y), Child.DesiredSize));
  210. }
  211. /// <summary>
  212. /// 绘制控件
  213. /// </summary>
  214. /// <param name="drawingContext"></param>
  215. protected override void OnRender(DrawingContext drawingContext)
  216. {
  217. if (Child != null)
  218. {
  219. Geometry cg = null;
  220. Brush brush = null;
  221. //DpiScale dpi = base.getd();
  222. Pen pen = new Pen();
  223. pen.Brush = this.BorderBrush;
  224. //pen.Thickness = BorderThickness * 0.5;
  225. pen.Thickness = UIElementEx.RoundLayoutValue(BorderThickness.Left, DoubleUtil.DpiScaleX);
  226. switch (Placement)
  227. {
  228. case EnumPlacement.LeftTop:
  229. case EnumPlacement.LeftBottom:
  230. case EnumPlacement.LeftCenter:
  231. //生成小尾巴在左侧的图形和底色
  232. cg = CreateGeometryTailAtLeft();
  233. brush = CreateFillBrush();
  234. break;
  235. case EnumPlacement.RightTop:
  236. case EnumPlacement.RightCenter:
  237. case EnumPlacement.RightBottom:
  238. //生成小尾巴在右侧的图形和底色
  239. cg = CreateGeometryTailAtRight();
  240. brush = CreateFillBrush();
  241. break;
  242. case EnumPlacement.TopLeft:
  243. case EnumPlacement.TopCenter:
  244. case EnumPlacement.TopRight:
  245. //生成小尾巴在右侧的图形和底色
  246. cg = CreateGeometryTailAtTop();
  247. brush = CreateFillBrush();
  248. break;
  249. case EnumPlacement.BottomLeft:
  250. case EnumPlacement.BottomCenter:
  251. case EnumPlacement.BottomRight:
  252. //生成小尾巴在右侧的图形和底色
  253. cg = CreateGeometryTailAtBottom();
  254. brush = CreateFillBrush();
  255. break;
  256. default:
  257. break;
  258. }
  259. GuidelineSet guideLines = new GuidelineSet();
  260. drawingContext.PushGuidelineSet(guideLines);
  261. drawingContext.DrawGeometry(brush, pen, cg);
  262. }
  263. }
  264. #endregion
  265. #region 私有方法
  266. private Geometry CreateGeometryTailAtRight()
  267. {
  268. CombinedGeometry result = new CombinedGeometry();
  269. this.TailHeight = 12;
  270. this.TailWidth = 6;
  271. switch (this.Placement)
  272. {
  273. case EnumPlacement.RightTop:
  274. //不做任何处理
  275. break;
  276. case EnumPlacement.RightBottom:
  277. this.TailVerticalOffset = this.ActualHeight - this.TailHeight - this.TailVerticalOffset;
  278. break;
  279. case EnumPlacement.RightCenter:
  280. this.TailVerticalOffset = (this.ActualHeight - this.TailHeight) / 2;
  281. break;
  282. }
  283. #region 绘制三角形
  284. Point arcPoint1 = new Point(this.ActualWidth - TailWidth, TailVerticalOffset);
  285. Point arcPoint2 = new Point(this.ActualWidth, TailVerticalOffset + TailHeight / 2);
  286. Point arcPoint3 = new Point(this.ActualWidth - TailWidth, TailVerticalOffset + TailHeight);
  287. LineSegment as1_2 = new LineSegment(arcPoint2, false);
  288. LineSegment as2_3 = new LineSegment(arcPoint3, false);
  289. PathFigure pf1 = new PathFigure();
  290. pf1.IsClosed = false;
  291. pf1.StartPoint = arcPoint1;
  292. pf1.Segments.Add(as1_2);
  293. pf1.Segments.Add(as2_3);
  294. PathGeometry pg1 = new PathGeometry();
  295. pg1.Figures.Add(pf1);
  296. #endregion
  297. #region 绘制矩形边框
  298. RectangleGeometry rg2 = new RectangleGeometry(new Rect(0, 0, this.ActualWidth - TailWidth, this.ActualHeight)
  299. , CornerRadius.TopLeft, CornerRadius.BottomRight, new TranslateTransform(0.5, 0.5));
  300. #endregion
  301. #region 合并两个图形
  302. result.Geometry1 = pg1;
  303. result.Geometry2 = rg2;
  304. result.GeometryCombineMode = GeometryCombineMode.Union;
  305. #endregion
  306. return result;
  307. }
  308. private Geometry CreateGeometryTailAtLeft()
  309. {
  310. CombinedGeometry result = new CombinedGeometry();
  311. this.TailHeight = 12;
  312. this.TailWidth = 6;
  313. switch (this.Placement)
  314. {
  315. case EnumPlacement.LeftTop:
  316. //不做任何处理
  317. break;
  318. case EnumPlacement.LeftBottom:
  319. this.TailVerticalOffset = this.ActualHeight - this.TailHeight - this.TailVerticalOffset;
  320. break;
  321. case EnumPlacement.LeftCenter:
  322. this.TailVerticalOffset = (this.ActualHeight - this.TailHeight) / 2;
  323. break;
  324. }
  325. #region 绘制三角形
  326. Point arcPoint1 = new Point(TailWidth, TailVerticalOffset);
  327. Point arcPoint2 = new Point(0, TailVerticalOffset + TailHeight / 2);
  328. Point arcPoint3 = new Point(TailWidth, TailVerticalOffset + TailHeight);
  329. LineSegment as1_2 = new LineSegment(arcPoint2, false);
  330. LineSegment as2_3 = new LineSegment(arcPoint3, false);
  331. PathFigure pf = new PathFigure();
  332. pf.IsClosed = false;
  333. pf.StartPoint = arcPoint1;
  334. pf.Segments.Add(as1_2);
  335. pf.Segments.Add(as2_3);
  336. PathGeometry g1 = new PathGeometry();
  337. g1.Figures.Add(pf);
  338. #endregion
  339. #region 绘制矩形边框
  340. RectangleGeometry g2 = new RectangleGeometry(new Rect(TailWidth, 0, this.ActualWidth - this.TailWidth, this.ActualHeight)
  341. , CornerRadius.TopLeft, CornerRadius.BottomRight);
  342. #endregion
  343. #region 合并两个图形
  344. result.Geometry1 = g1;
  345. result.Geometry2 = g2;
  346. result.GeometryCombineMode = GeometryCombineMode.Union;
  347. #endregion
  348. return result;
  349. }
  350. private Geometry CreateGeometryTailAtTop()
  351. {
  352. CombinedGeometry result = new CombinedGeometry();
  353. switch (this.Placement)
  354. {
  355. case EnumPlacement.TopLeft:
  356. break;
  357. case EnumPlacement.TopCenter:
  358. this.TailHorizontalOffset = (this.ActualWidth - this.TailWidth) / 2;
  359. break;
  360. case EnumPlacement.TopRight:
  361. this.TailHorizontalOffset = this.ActualWidth - this.TailWidth - this.TailHorizontalOffset;
  362. break;
  363. }
  364. #region 绘制三角形
  365. Point anglePoint1 = new Point(this.TailHorizontalOffset, this.TailHeight);
  366. Point anglePoint2 = new Point(this.TailHorizontalOffset + (this.TailWidth / 2), 0);
  367. Point anglePoint3 = new Point(this.TailHorizontalOffset + this.TailWidth, this.TailHeight);
  368. LineSegment as1_2 = new LineSegment(anglePoint2, true);
  369. LineSegment as2_3 = new LineSegment(anglePoint3, true);
  370. PathFigure pf = new PathFigure();
  371. pf.IsClosed = false;
  372. pf.StartPoint = anglePoint1;
  373. pf.Segments.Add(as1_2);
  374. pf.Segments.Add(as2_3);
  375. PathGeometry g1 = new PathGeometry();
  376. g1.Figures.Add(pf);
  377. #endregion
  378. #region 绘制矩形边框
  379. RectangleGeometry g2 = new RectangleGeometry(new Rect(0, this.TailHeight, this.ActualWidth, this.ActualHeight - this.TailHeight)
  380. , CornerRadius.TopLeft, CornerRadius.BottomRight);
  381. #endregion
  382. #region 合并
  383. result.Geometry1 = g1;
  384. result.Geometry2 = g2;
  385. result.GeometryCombineMode = GeometryCombineMode.Union;
  386. #endregion
  387. return result;
  388. }
  389. private Geometry CreateGeometryTailAtBottom()
  390. {
  391. CombinedGeometry result = new CombinedGeometry();
  392. switch (this.Placement)
  393. {
  394. case EnumPlacement.BottomLeft:
  395. break;
  396. case EnumPlacement.BottomCenter:
  397. this.TailHorizontalOffset = (this.ActualWidth - this.TailWidth) / 2;
  398. break;
  399. case EnumPlacement.BottomRight:
  400. this.TailHorizontalOffset = this.ActualWidth - this.TailWidth - this.TailHorizontalOffset;
  401. break;
  402. }
  403. #region 绘制三角形
  404. Point anglePoint1 = new Point(this.TailHorizontalOffset, this.ActualHeight - this.TailHeight);
  405. Point anglePoint2 = new Point(this.TailHorizontalOffset + this.TailWidth / 2, this.ActualHeight);
  406. Point anglePoint3 = new Point(this.TailHorizontalOffset + this.TailWidth, this.ActualHeight - this.TailHeight);
  407. LineSegment as1_2 = new LineSegment(anglePoint2, true);
  408. LineSegment as2_3 = new LineSegment(anglePoint3, true);
  409. PathFigure pf = new PathFigure();
  410. pf.IsClosed = false;
  411. pf.StartPoint = anglePoint1;
  412. pf.Segments.Add(as1_2);
  413. pf.Segments.Add(as2_3);
  414. PathGeometry g1 = new PathGeometry();
  415. g1.Figures.Add(pf);
  416. #endregion
  417. #region 绘制矩形边框
  418. RectangleGeometry g2 = new RectangleGeometry(new Rect(0, 0, this.ActualWidth, this.ActualHeight - this.TailHeight)
  419. , CornerRadius.TopLeft, CornerRadius.BottomRight);
  420. #endregion
  421. #region 合并
  422. result.Geometry1 = g1;
  423. result.Geometry2 = g2;
  424. result.GeometryCombineMode = GeometryCombineMode.Union;
  425. #endregion
  426. return result;
  427. }
  428. private Brush CreateFillBrush()
  429. {
  430. Brush result = null;
  431. GradientStopCollection gsc = new GradientStopCollection();
  432. gsc.Add(new GradientStop(((SolidColorBrush)this.Background).Color, 0));
  433. LinearGradientBrush backGroundBrush = new LinearGradientBrush(gsc, new Point(0, 0), new Point(0, 1));
  434. result = backGroundBrush;
  435. return result;
  436. }
  437. /// <summary>
  438. /// 根据三角形方向设置消息框的水平位置,偏左还是偏右
  439. /// </summary>
  440. /// <param name="d"></param>
  441. /// <param name="e"></param>
  442. public static void OnDirectionPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
  443. {
  444. AngleBorder angleBorder = d as AngleBorder;
  445. if(angleBorder != null)
  446. {
  447. switch ((EnumPlacement)e.NewValue)
  448. {
  449. case EnumPlacement.LeftTop:
  450. case EnumPlacement.LeftBottom:
  451. case EnumPlacement.LeftCenter:
  452. case EnumPlacement.RightTop:
  453. case EnumPlacement.RightBottom:
  454. case EnumPlacement.RightCenter:
  455. angleBorder.TailWidth = 6;
  456. angleBorder.TailHeight = 12;
  457. break;
  458. case EnumPlacement.TopLeft:
  459. case EnumPlacement.TopCenter:
  460. case EnumPlacement.TopRight:
  461. case EnumPlacement.BottomLeft:
  462. case EnumPlacement.BottomCenter:
  463. case EnumPlacement.BottomRight:
  464. angleBorder.TailWidth = 12;
  465. angleBorder.TailHeight = 6;
  466. break;
  467. default:
  468. break;
  469. }
  470. }
  471. }
  472. #endregion
  473. }
  474. public class DoubleUtil
  475. {
  476. public static double DpiScaleX
  477. {
  478. get
  479. {
  480. int dx = 0;
  481. int dy = 0;
  482. GetDPI(out dx, out dy);
  483. if (dx != 96)
  484. {
  485. return (double)dx / 96.0;
  486. }
  487. return 1.0;
  488. }
  489. }
  490. public static double DpiScaleY
  491. {
  492. get
  493. {
  494. int dx = 0;
  495. int dy = 0;
  496. GetDPI(out dx, out dy);
  497. if (dy != 96)
  498. {
  499. return (double)dy / 96.0;
  500. }
  501. return 1.0;
  502. }
  503. }
  504. public static void GetDPI(out int dpix, out int dpiy)
  505. {
  506. dpix = 0;
  507. dpiy = 0;
  508. using (System.Management.ManagementClass mc = new System.Management.ManagementClass("Win32_DesktopMonitor"))
  509. {
  510. using (System.Management.ManagementObjectCollection moc = mc.GetInstances())
  511. {
  512. foreach (System.Management.ManagementObject each in moc)
  513. {
  514. dpix = int.Parse((each.Properties["PixelsPerXLogicalInch"].Value.ToString()));
  515. dpiy = int.Parse((each.Properties["PixelsPerYLogicalInch"].Value.ToString()));
  516. }
  517. }
  518. }
  519. }
  520. public static bool GreaterThan(double value1, double value2)
  521. {
  522. return value1 > value2 && !DoubleUtil.AreClose(value1, value2);
  523. }
  524. public static bool AreClose(double value1, double value2)
  525. {
  526. if (value1 == value2)
  527. {
  528. return true;
  529. }
  530. double num = (Math.Abs(value1) + Math.Abs(value2) + 10.0) * 2.2204460492503131E-16;
  531. double num2 = value1 - value2;
  532. return -num < num2 && num > num2;
  533. }
  534. public static bool IsZero(double value)
  535. {
  536. return Math.Abs(value) < 2.2204460492503131E-15;
  537. }
  538. [StructLayout(LayoutKind.Explicit)]
  539. private struct NanUnion
  540. {
  541. [FieldOffset(0)]
  542. internal double DoubleValue;
  543. [FieldOffset(0)]
  544. internal ulong UintValue;
  545. }
  546. public static bool IsNaN(double value)
  547. {
  548. DoubleUtil.NanUnion nanUnion = default(DoubleUtil.NanUnion);
  549. nanUnion.DoubleValue = value;
  550. ulong num = nanUnion.UintValue & 18442240474082181120uL;
  551. ulong num2 = nanUnion.UintValue & 4503599627370495uL;
  552. return (num == 9218868437227405312uL || num == 18442240474082181120uL) && num2 != 0uL;
  553. }
  554. }
  555. public static class UlementEx
  556. {
  557. public static double RoundLayoutValue(double value, double dpiScale)
  558. {
  559. double num;
  560. if (!DoubleUtil.AreClose(dpiScale, 1.0))
  561. {
  562. num = Math.Round(value * dpiScale) / dpiScale;
  563. if (DoubleUtil.IsNaN(num) || double.IsInfinity(num) || DoubleUtil.AreClose(num, 1.7976931348623157E+308))
  564. {
  565. num = value;
  566. }
  567. }
  568. else
  569. {
  570. num = Math.Round(value);
  571. }
  572. return num;
  573. }
  574. }
  575. }