HtmlControl.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
  1. // "Therefore those skilled at the unorthodox
  2. // are infinite as heaven and earth,
  3. // inexhaustible as the great rivers.
  4. // When they come to an end,
  5. // they begin again,
  6. // like the days and months;
  7. // they die and are reborn,
  8. // like the four seasons."
  9. //
  10. // - Sun Tsu,
  11. // "The Art of War"
  12. using System;
  13. using Perspex.Controls.Primitives;
  14. using Perspex.HtmlRenderer;
  15. using Perspex.Input;
  16. using Perspex.Interactivity;
  17. using Perspex.Media;
  18. using Perspex.Threading;
  19. using TheArtOfDev.HtmlRenderer.Core;
  20. using TheArtOfDev.HtmlRenderer.Core.Entities;
  21. using TheArtOfDev.HtmlRenderer.Perspex;
  22. using TheArtOfDev.HtmlRenderer.Perspex.Adapters;
  23. namespace Perspex.Controls.Html
  24. {
  25. /// <summary>
  26. /// Provides HTML rendering using the text property.<br/>
  27. /// Perspex control that will render html content in it's client rectangle.<br/>
  28. /// The control will handle mouse and keyboard events on it to support html text selection, copy-paste and mouse clicks.<br/>
  29. /// <para>
  30. /// The major differential to use HtmlPanel or HtmlLabel is size and scrollbars.<br/>
  31. /// If the size of the control depends on the html content the HtmlLabel should be used.<br/>
  32. /// If the size is set by some kind of layout then HtmlPanel is more suitable, also shows scrollbars if the html contents is larger than the control client rectangle.<br/>
  33. /// </para>
  34. /// <para>
  35. /// <h4>LinkClicked event:</h4>
  36. /// Raised when the user clicks on a link in the html.<br/>
  37. /// Allows canceling the execution of the link.
  38. /// </para>
  39. /// <para>
  40. /// <h4>StylesheetLoad event:</h4>
  41. /// Raised when a stylesheet is about to be loaded by file path or URI by link element.<br/>
  42. /// This event allows to provide the stylesheet manually or provide new source (file or uri) to load from.<br/>
  43. /// If no alternative data is provided the original source will be used.<br/>
  44. /// </para>
  45. /// <para>
  46. /// <h4>ImageLoad event:</h4>
  47. /// Raised when an image is about to be loaded by file path or URI.<br/>
  48. /// This event allows to provide the image manually, if not handled the image will be loaded from file or download from URI.
  49. /// </para>
  50. /// <para>
  51. /// <h4>RenderError event:</h4>
  52. /// Raised when an error occurred during html rendering.<br/>
  53. /// </para>
  54. /// </summary>
  55. public class HtmlControl : Control
  56. {
  57. /// <summary>
  58. /// Underline html container instance.
  59. /// </summary>
  60. protected readonly HtmlContainer _htmlContainer;
  61. /// <summary>
  62. /// the base stylesheet data used in the control
  63. /// </summary>
  64. protected CssData _baseCssData;
  65. /// <summary>
  66. /// The last position of the scrollbars to know if it has changed to update mouse
  67. /// </summary>
  68. protected Point _lastScrollOffset;
  69. public static readonly PerspexProperty AvoidImagesLateLoadingProperty =
  70. PropertyHelper.Register<HtmlControl, bool>("AvoidImagesLateLoading", false, OnPerspexProperty_valueChanged);
  71. public static readonly PerspexProperty IsSelectionEnabledProperty =
  72. PropertyHelper.Register<HtmlControl, bool>("IsSelectionEnabled", true, OnPerspexProperty_valueChanged);
  73. public static readonly PerspexProperty IsContextMenuEnabledProperty =
  74. PropertyHelper.Register<HtmlControl, bool>("IsContextMenuEnabled", true, OnPerspexProperty_valueChanged);
  75. public static readonly PerspexProperty BaseStylesheetProperty =
  76. PropertyHelper.Register<HtmlControl, string>("BaseStylesheet", null, OnPerspexProperty_valueChanged);
  77. public static readonly PerspexProperty TextProperty =
  78. PropertyHelper.Register<HtmlControl, string>("Text", null, OnPerspexProperty_valueChanged);
  79. public static readonly StyledProperty<Brush> BackgroundProperty =
  80. Border.BackgroundProperty.AddOwner<HtmlControl>();
  81. public static readonly PerspexProperty BorderThicknessProperty =
  82. PerspexProperty.Register<HtmlControl, Thickness>("BorderThickness", new Thickness(0));
  83. public static readonly PerspexProperty BorderBrushProperty =
  84. PerspexProperty.Register<HtmlControl, Brush>("BorderBrush");
  85. public static readonly PerspexProperty PaddingProperty =
  86. PerspexProperty.Register<HtmlControl, Thickness>("Padding", new Thickness(0));
  87. public static readonly RoutedEvent LoadCompleteEvent =
  88. RoutedEvent.Register<RoutedEventArgs>("LoadComplete", RoutingStrategies.Bubble, typeof(HtmlControl));
  89. public static readonly RoutedEvent LinkClickedEvent =
  90. RoutedEvent.Register<HtmlRendererRoutedEventArgs<HtmlLinkClickedEventArgs>>("LinkClicked", RoutingStrategies.Bubble, typeof(HtmlControl));
  91. public static readonly RoutedEvent RenderErrorEvent
  92. = RoutedEvent.Register<HtmlRendererRoutedEventArgs<HtmlRenderErrorEventArgs>>("RenderError", RoutingStrategies.Bubble, typeof(HtmlControl));
  93. public static readonly RoutedEvent RefreshEvent
  94. = RoutedEvent.Register<HtmlRendererRoutedEventArgs<HtmlRefreshEventArgs>>("Refresh", RoutingStrategies.Bubble, typeof(HtmlControl));
  95. public static readonly RoutedEvent StylesheetLoadEvent
  96. = RoutedEvent.Register<HtmlRendererRoutedEventArgs<HtmlStylesheetLoadEventArgs>>("StylesheetLoad", RoutingStrategies.Bubble, typeof(HtmlControl));
  97. public static readonly RoutedEvent ImageLoadEvent
  98. = RoutedEvent.Register<HtmlRendererRoutedEventArgs<HtmlImageLoadEventArgs>>("ImageLoad", RoutingStrategies.Bubble,
  99. typeof (HtmlControl));
  100. static HtmlControl()
  101. {
  102. FocusableProperty.OverrideDefaultValue(typeof(HtmlControl), true);
  103. }
  104. /// <summary>
  105. /// Creates a new HtmlPanel and sets a basic css for it's styling.
  106. /// </summary>
  107. protected HtmlControl()
  108. {
  109. _htmlContainer = new HtmlContainer();
  110. _htmlContainer.LoadComplete += (_, e) => OnLoadComplete(e);
  111. _htmlContainer.LinkClicked += (_, e) => OnLinkClicked(e);
  112. _htmlContainer.RenderError += (_, e) => OnRenderError(e);
  113. _htmlContainer.Refresh += (_, e) => OnRefresh(e);
  114. _htmlContainer.StylesheetLoad += (_, e) => OnStylesheetLoad(e);
  115. _htmlContainer.ImageLoad += (_, e) => OnImageLoad(e);
  116. }
  117. //Hack for adapter
  118. internal bool LeftMouseButton { get; private set; }
  119. /// <summary>
  120. /// Raised when the set html document has been fully loaded.<br/>
  121. /// Allows manipulation of the html dom, scroll position, etc.
  122. /// </summary>
  123. public event EventHandler<HtmlRendererRoutedEventArgs<EventArgs>> LoadComplete
  124. {
  125. add { AddHandler(LoadCompleteEvent, value); }
  126. remove { RemoveHandler(LoadCompleteEvent, value); }
  127. }
  128. /// <summary>
  129. /// Raised when the user clicks on a link in the html.<br/>
  130. /// Allows canceling the execution of the link.
  131. /// </summary>
  132. public event EventHandler<HtmlRendererRoutedEventArgs<HtmlLinkClickedEventArgs>> LinkClicked
  133. {
  134. add { AddHandler(LinkClickedEvent, value); }
  135. remove { RemoveHandler(LinkClickedEvent, value); }
  136. }
  137. /// <summary>
  138. /// Raised when an error occurred during html rendering.<br/>
  139. /// </summary>
  140. public event EventHandler<HtmlRendererRoutedEventArgs<HtmlRenderErrorEventArgs>> RenderError
  141. {
  142. add { AddHandler(RenderErrorEvent, value); }
  143. remove { RemoveHandler(RenderErrorEvent, value); }
  144. }
  145. /// <summary>
  146. /// Raised when a stylesheet is about to be loaded by file path or URI by link element.<br/>
  147. /// This event allows to provide the stylesheet manually or provide new source (file or uri) to load from.<br/>
  148. /// If no alternative data is provided the original source will be used.<br/>
  149. /// </summary>
  150. public event EventHandler<HtmlRendererRoutedEventArgs<HtmlStylesheetLoadEventArgs>> StylesheetLoad
  151. {
  152. add { AddHandler(StylesheetLoadEvent, value); }
  153. remove { RemoveHandler(StylesheetLoadEvent, value); }
  154. }
  155. /// <summary>
  156. /// Raised when an image is about to be loaded by file path or URI.<br/>
  157. /// This event allows to provide the image manually, if not handled the image will be loaded from file or download from URI.
  158. /// </summary>
  159. public event EventHandler<HtmlRendererRoutedEventArgs<HtmlImageLoadEventArgs>> ImageLoad
  160. {
  161. add { AddHandler(ImageLoadEvent, value); }
  162. remove { RemoveHandler(ImageLoadEvent, value); }
  163. }
  164. /// <summary>
  165. /// Gets or sets a value indicating if image loading only when visible should be avoided (default - false).<br/>
  166. /// True - images are loaded as soon as the html is parsed.<br/>
  167. /// False - images that are not visible because of scroll location are not loaded until they are scrolled to.
  168. /// </summary>
  169. /// <remarks>
  170. /// Images late loading improve performance if the page contains image outside the visible scroll area, especially if there is large
  171. /// amount of images, as all image loading is delayed (downloading and loading into memory).<br/>
  172. /// Late image loading may effect the layout and actual size as image without set size will not have actual size until they are loaded
  173. /// resulting in layout change during user scroll.<br/>
  174. /// Early image loading may also effect the layout if image without known size above the current scroll location are loaded as they
  175. /// will push the html elements down.
  176. /// </remarks>
  177. [Category("Behavior")]
  178. [Description("If image loading only when visible should be avoided")]
  179. public bool AvoidImagesLateLoading
  180. {
  181. get { return (bool)GetValue(AvoidImagesLateLoadingProperty); }
  182. set { SetValue(AvoidImagesLateLoadingProperty, value); }
  183. }
  184. /// <summary>
  185. /// Is content selection is enabled for the rendered html (default - true).<br/>
  186. /// If set to 'false' the rendered html will be static only with ability to click on links.
  187. /// </summary>
  188. [Category("Behavior")]
  189. [Description("Is content selection is enabled for the rendered html.")]
  190. public bool IsSelectionEnabled
  191. {
  192. get { return (bool)GetValue(IsSelectionEnabledProperty); }
  193. set { SetValue(IsSelectionEnabledProperty, value); }
  194. }
  195. /// <summary>
  196. /// Is the build-in context menu enabled and will be shown on mouse right click (default - true)
  197. /// </summary>
  198. [Category("Behavior")]
  199. [Description("Is the build-in context menu enabled and will be shown on mouse right click.")]
  200. public bool IsContextMenuEnabled
  201. {
  202. get { return (bool)GetValue(IsContextMenuEnabledProperty); }
  203. set { SetValue(IsContextMenuEnabledProperty, value); }
  204. }
  205. /// <summary>
  206. /// Set base stylesheet to be used by html rendered in the panel.
  207. /// </summary>
  208. [Category("Appearance")]
  209. [Description("Set base stylesheet to be used by html rendered in the control.")]
  210. public string BaseStylesheet
  211. {
  212. get { return (string)GetValue(BaseStylesheetProperty); }
  213. set { SetValue(BaseStylesheetProperty, value); }
  214. }
  215. /// <summary>
  216. /// Gets or sets the text of this panel
  217. /// </summary>
  218. [Description("Sets the html of this control.")]
  219. public string Text
  220. {
  221. get { return (string)GetValue(TextProperty); }
  222. set { SetValue(TextProperty, value); }
  223. }
  224. public Thickness BorderThickness
  225. {
  226. get { return (Thickness) GetValue(BorderThicknessProperty); }
  227. set { SetValue(BorderThicknessProperty, value); }
  228. }
  229. public Brush BorderBrush
  230. {
  231. get { return (Brush)GetValue(BorderBrushProperty); }
  232. set { SetValue(BorderThicknessProperty, value); }
  233. }
  234. public Thickness Padding
  235. {
  236. get { return (Thickness)GetValue(PaddingProperty); }
  237. set { SetValue(PaddingProperty, value); }
  238. }
  239. public Brush Background
  240. {
  241. get { return (Brush) GetValue(BackgroundProperty); }
  242. set { SetValue(BackgroundProperty, value);}
  243. }
  244. /// <summary>
  245. /// Get the currently selected text segment in the html.
  246. /// </summary>
  247. [Browsable(false)]
  248. public virtual string SelectedText
  249. {
  250. get { return _htmlContainer.SelectedText; }
  251. }
  252. /// <summary>
  253. /// Copy the currently selected html segment with style.
  254. /// </summary>
  255. [Browsable(false)]
  256. public virtual string SelectedHtml
  257. {
  258. get { return _htmlContainer.SelectedHtml; }
  259. }
  260. /// <summary>
  261. /// Get html from the current DOM tree with inline style.
  262. /// </summary>
  263. /// <returns>generated html</returns>
  264. public virtual string GetHtml()
  265. {
  266. return _htmlContainer != null ? _htmlContainer.GetHtml() : null;
  267. }
  268. /// <summary>
  269. /// Get the rectangle of html element as calculated by html layout.<br/>
  270. /// Element if found by id (id attribute on the html element).<br/>
  271. /// Note: to get the screen rectangle you need to adjust by the hosting control.<br/>
  272. /// </summary>
  273. /// <param name="elementId">the id of the element to get its rectangle</param>
  274. /// <returns>the rectangle of the element or null if not found</returns>
  275. public virtual Rect? GetElementRectangle(string elementId)
  276. {
  277. return _htmlContainer != null ? _htmlContainer.GetElementRectangle(elementId) : null;
  278. }
  279. /// <summary>
  280. /// Clear the current selection.
  281. /// </summary>
  282. public void ClearSelection()
  283. {
  284. if (_htmlContainer != null)
  285. _htmlContainer.ClearSelection();
  286. }
  287. //HACK: We don't have support for RenderSize for now
  288. private Size RenderSize => new Size(Bounds.Width, Bounds.Height);
  289. public override void Render(DrawingContext context)
  290. {
  291. context.FillRectangle(Background, new Rect(RenderSize));
  292. if (BorderThickness != new Thickness(0) && BorderBrush != null)
  293. {
  294. var brush = new SolidColorBrush(Colors.Black);
  295. if (BorderThickness.Top > 0)
  296. context.FillRectangle(brush, new Rect(0, 0, RenderSize.Width, BorderThickness.Top));
  297. if (BorderThickness.Bottom > 0)
  298. context.FillRectangle(brush, new Rect(0, RenderSize.Height - BorderThickness.Bottom, RenderSize.Width, BorderThickness.Bottom));
  299. if (BorderThickness.Left > 0)
  300. context.FillRectangle(brush, new Rect(0, 0, BorderThickness.Left, RenderSize.Height));
  301. if (BorderThickness.Right > 0)
  302. context.FillRectangle(brush, new Rect(RenderSize.Width - BorderThickness.Right, 0, BorderThickness.Right, RenderSize.Height));
  303. }
  304. var htmlWidth = HtmlWidth(RenderSize);
  305. var htmlHeight = HtmlHeight(RenderSize);
  306. if (_htmlContainer != null && htmlWidth > 0 && htmlHeight > 0)
  307. {
  308. /*
  309. //TODO: Revert antialiasing fixes
  310. var windows = Window.GetWindow(this);
  311. if (windows != null)
  312. {
  313. // adjust render location to round point so we won't get anti-alias smugness
  314. var wPoint = TranslatePoint(new Point(0, 0), windows);
  315. wPoint.Offset(-(int)wPoint.X, -(int)wPoint.Y);
  316. var xTrans = wPoint.X < .5 ? -wPoint.X : 1 - wPoint.X;
  317. var yTrans = wPoint.Y < .5 ? -wPoint.Y : 1 - wPoint.Y;
  318. context.PushTransform(new TranslateTransform(xTrans, yTrans));
  319. }*/
  320. using (context.PushClip(new Rect(Padding.Left + BorderThickness.Left, Padding.Top + BorderThickness.Top,
  321. htmlWidth, (int) htmlHeight)))
  322. {
  323. _htmlContainer.Location = new Point(Padding.Left + BorderThickness.Left,
  324. Padding.Top + BorderThickness.Top);
  325. _htmlContainer.PerformPaint(context,
  326. new Rect(Padding.Left + BorderThickness.Left, Padding.Top + BorderThickness.Top, htmlWidth,
  327. htmlHeight));
  328. }
  329. if (!_lastScrollOffset.Equals(_htmlContainer.ScrollOffset))
  330. {
  331. _lastScrollOffset = _htmlContainer.ScrollOffset;
  332. InvokeMouseMove();
  333. }
  334. }
  335. }
  336. /// <summary>
  337. /// Handle mouse move to handle hover cursor and text selection.
  338. /// </summary>
  339. protected override void OnPointerMoved(PointerEventArgs e)
  340. {
  341. base.OnPointerMoved(e);
  342. if (_htmlContainer != null)
  343. _htmlContainer.HandleMouseMove(this, e.GetPosition(this));
  344. }
  345. /// <summary>
  346. /// Handle mouse leave to handle cursor change.
  347. /// </summary>
  348. protected override void OnPointerLeave(PointerEventArgs e)
  349. {
  350. base.OnPointerLeave(e);
  351. if (_htmlContainer != null)
  352. _htmlContainer.HandleMouseLeave(this);
  353. }
  354. /// <summary>
  355. /// Handle mouse down to handle selection.
  356. /// </summary>
  357. protected override void OnPointerPressed(PointerPressEventArgs e)
  358. {
  359. base.OnPointerPressed(e);
  360. LeftMouseButton = true;
  361. _htmlContainer?.HandleLeftMouseDown(this, e);
  362. }
  363. /// <summary>
  364. /// Handle mouse up to handle selection and link click.
  365. /// </summary>
  366. protected override void OnPointerReleased(PointerEventArgs e)
  367. {
  368. base.OnPointerReleased(e);
  369. LeftMouseButton = false;
  370. if (_htmlContainer != null)
  371. _htmlContainer.HandleLeftMouseUp(this, e);
  372. }
  373. //TODO: Implement double click
  374. /*
  375. /// <summary>
  376. /// Handle mouse double click to select word under the mouse.
  377. /// </summary>
  378. protected override void OnMouseDoubleClick(MouseButtonEventArgs e)
  379. {
  380. base.OnMouseDoubleClick(e);
  381. if (_htmlContainer != null)
  382. _htmlContainer.HandleMouseDoubleClick(this, e);
  383. }
  384. */
  385. /// <summary>
  386. /// Handle key down event for selection, copy and scrollbars handling.
  387. /// </summary>
  388. protected override void OnKeyDown(KeyEventArgs e)
  389. {
  390. base.OnKeyDown(e);
  391. if (_htmlContainer != null)
  392. _htmlContainer.HandleKeyDown(this, e);
  393. }
  394. void RaiseRouted<T>(RoutedEvent ev, T arg)
  395. {
  396. var e =new HtmlRendererRoutedEventArgs<T>
  397. {
  398. Event = arg,
  399. Source = this,
  400. RoutedEvent = ev,
  401. Route = ev.RoutingStrategies
  402. };
  403. RaiseEvent(e);
  404. }
  405. /// <summary>
  406. /// Propagate the LoadComplete event from root container.
  407. /// </summary>
  408. protected virtual void OnLoadComplete(EventArgs e) => RaiseRouted(LoadCompleteEvent, e);
  409. /// <summary>
  410. /// Propagate the LinkClicked event from root container.
  411. /// </summary>
  412. protected virtual void OnLinkClicked(HtmlLinkClickedEventArgs e) => RaiseRouted(LinkClickedEvent, e);
  413. /// <summary>
  414. /// Propagate the Render Error event from root container.
  415. /// </summary>
  416. protected virtual void OnRenderError(HtmlRenderErrorEventArgs e) => RaiseRouted(RenderErrorEvent, e);
  417. /// <summary>
  418. /// Propagate the stylesheet load event from root container.
  419. /// </summary>
  420. protected virtual void OnStylesheetLoad(HtmlStylesheetLoadEventArgs e) => RaiseRouted(StylesheetLoadEvent, e);
  421. /// <summary>
  422. /// Propagate the image load event from root container.
  423. /// </summary>
  424. protected virtual void OnImageLoad(HtmlImageLoadEventArgs e) => RaiseRouted(ImageLoadEvent, e);
  425. /// <summary>
  426. /// Handle html renderer invalidate and re-layout as requested.
  427. /// </summary>
  428. protected virtual void OnRefresh(HtmlRefreshEventArgs e)
  429. {
  430. if (e.Layout)
  431. InvalidateMeasure();
  432. InvalidateVisual();
  433. }
  434. /// <summary>
  435. /// Get the width the HTML has to render in (not including vertical scroll iff it is visible)
  436. /// </summary>
  437. protected virtual double HtmlWidth(Size size)
  438. {
  439. return size.Width - Padding.Left - Padding.Right - BorderThickness.Left - BorderThickness.Right;
  440. }
  441. /// <summary>
  442. /// Get the width the HTML has to render in (not including vertical scroll iff it is visible)
  443. /// </summary>
  444. protected virtual double HtmlHeight(Size size)
  445. {
  446. return size.Height - Padding.Top - Padding.Bottom - BorderThickness.Top - BorderThickness.Bottom;
  447. }
  448. /// <summary>
  449. /// call mouse move to handle paint after scroll or html change affecting mouse cursor.
  450. /// </summary>
  451. protected virtual void InvokeMouseMove()
  452. {
  453. _htmlContainer.HandleMouseMove(this, MouseDevice.Instance?.GetPosition(this) ?? default(Point));
  454. }
  455. /// <summary>
  456. /// Handle when dependency property value changes to update the underline HtmlContainer with the new value.
  457. /// </summary>
  458. private static void OnPerspexProperty_valueChanged(PerspexObject PerspexObject,
  459. PerspexPropertyChangedEventArgs e)
  460. {
  461. var control = PerspexObject as HtmlControl;
  462. if (control != null)
  463. {
  464. var htmlContainer = control._htmlContainer;
  465. if (e.Property == AvoidImagesLateLoadingProperty)
  466. {
  467. htmlContainer.AvoidImagesLateLoading = (bool) e.NewValue;
  468. }
  469. else if (e.Property == IsSelectionEnabledProperty)
  470. {
  471. htmlContainer.IsSelectionEnabled = (bool) e.NewValue;
  472. }
  473. else if (e.Property == IsContextMenuEnabledProperty)
  474. {
  475. htmlContainer.IsContextMenuEnabled = (bool) e.NewValue;
  476. }
  477. else if (e.Property == BaseStylesheetProperty)
  478. {
  479. var baseCssData = CssData.Parse(PerspexAdapter.Instance, (string) e.NewValue);
  480. control._baseCssData = baseCssData;
  481. htmlContainer.SetHtml(control.Text, baseCssData);
  482. }
  483. else if (e.Property == TextProperty)
  484. {
  485. htmlContainer.ScrollOffset = new Point(0, 0);
  486. htmlContainer.SetHtml((string) e.NewValue, control._baseCssData);
  487. control.InvalidateMeasure();
  488. control.InvalidateVisual();
  489. control.InvokeMouseMove();
  490. }
  491. }
  492. }
  493. //TODO: Implement CheckAccess calls
  494. /*
  495. private void OnLoadComplete(object sender, EventArgs e)
  496. {
  497. if (CheckAccess())
  498. OnLoadComplete(e);
  499. else
  500. Dispatcher.UIThread.Invoke(new Action<HtmlLinkClickedEventArgs>(OnLinkClicked), e);
  501. }
  502. private void OnLinkClicked(object sender, HtmlLinkClickedEventArgs e)
  503. {
  504. if (CheckAccess())
  505. OnLinkClicked(e);
  506. else
  507. Dispatcher.UIThread.Invoke(new Action<HtmlLinkClickedEventArgs>(OnLinkClicked), e);
  508. }
  509. private void OnRenderError(object sender, HtmlRenderErrorEventArgs e)
  510. {
  511. if (CheckAccess())
  512. OnRenderError(e);
  513. else
  514. Dispatcher.UIThread.Invoke(new Action<HtmlRenderErrorEventArgs>(OnRenderError), e);
  515. }
  516. private void OnStylesheetLoad(object sender, HtmlStylesheetLoadEventArgs e)
  517. {
  518. if (CheckAccess())
  519. OnStylesheetLoad(e);
  520. else
  521. Dispatcher.UIThread.Invoke(new Action<HtmlStylesheetLoadEventArgs>(OnStylesheetLoad), e);
  522. }
  523. private void OnImageLoad(object sender, HtmlImageLoadEventArgs e)
  524. {
  525. if (CheckAccess())
  526. OnImageLoad(e);
  527. else
  528. Dispatcher.UIThread.Invoke(new Action<HtmlImageLoadEventArgs>(OnImageLoad), e);
  529. }
  530. private void OnRefresh(object sender, HtmlRefreshEventArgs e)
  531. {
  532. if (CheckAccess())
  533. OnRefresh(e);
  534. else
  535. Dispatcher.UIThread.Invoke(new Action<HtmlRefreshEventArgs>(OnRefresh), e);
  536. }
  537. */
  538. }
  539. }