使用 MVVM 在 WPF 中显示 HTML
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7720946/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Displaying HTML in WPF using MVVM
提问by Shai
I have HTML-Source string saved in SQL Server table called "Report" in HTMLReport field (field type is NTEXT). Now I need to display that stored HTML into WPF Window. HTML tags and inline-CSS need to be interpreted on this WPF Window.
我在 HTMLReport 字段(字段类型为 NTEXT)的 SQL Server 表中保存了 HTML 源字符串,称为“报告”。现在我需要将存储的 HTML 显示到 WPF 窗口中。HTML 标记和内联 CSS 需要在此 WPF 窗口上进行解释。
Can someone help me to complete this code?
有人可以帮我完成这段代码吗?
HTMLView.xaml
HTMLView.xaml
<Window x:Class="MyProject.HTMLView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
Title="HTML View" Height="454" Width="787"
>
<Grid Name="grid1">
<WindowsFormsHost>
<wf:RichTextBox x:Name="reportHTML" Text="{Binding DisplayHTML, Mode=OneWay}"/>
<!-- How do i bind dispaly HTML page here-->
</WindowsFormsHost>
</Grid>
</Window>
HTMLViewModel.cs
HTMLViewModel.cs
namespace MyProject
{
public class HTMLViewModel: ViewModelBase
{
public HTMLViewModel()
{
//Reading from SQL Server table
//SELECT HTMLReport FROM Report WHERE ID=123
//OK, I have HTMLString from database over here
//Now I am assigning that to DisplayHTML Property
DisplayHTML ="<table><tr><td><b>This text should be in table with bold fond </b></td></tr></table>";
}
private string _displayHTML;
public string DisplayHTML
{
get
{
return _displayHTML;
}
set
{
if (_displayHTML!= value)
{
_displayHTML= value;
OnPropertyChanged("DisplayHTML");
}
}
}
}
回答by default.kramer
You'll probably want to use a WPF RichTextBox
instead of the Winforms one. Note that its Document
propertyis of type FlowDocument
. Since you have HTML, you will need a way to convert HTML to a FlowDocument
. This question and answerdescribe a way to do the conversion.
您可能想要使用WPFRichTextBox
而不是 Winforms。请注意,其Document
属性的类型为FlowDocument
。由于您拥有 HTML,因此您需要一种将 HTML 转换为FlowDocument
. 这个问题和答案描述了一种进行转换的方法。
回答by Jose
I created a control based on this article:
我根据这篇文章创建了一个控件:
...
...
public class ScrollableWebBrowser : WindowsFormsHost
{
[DllImport("GDI32.DLL", EntryPoint = "CreateRectRgn")]
private static extern IntPtr CreateRectRgn(Int32 x1, Int32 y1, Int32 x2, Int32 y2);
[DllImport("User32.dll", SetLastError = true)]
private static extern Int32 SetWindowRgn(IntPtr hWnd, IntPtr hRgn, Boolean bRedraw);
private Int32 _topLeftX = -1;
private Int32 _topLeftY = -1;
private Int32 _bottomRightX = -1;
private Int32 _bottomRightY = -1;
bool _disposed = false;
public static readonly DependencyProperty HtmlProperty = DependencyProperty.Register("Html", typeof(string), typeof(ScrollableWebBrowser), new PropertyMetadata(OnHtmlChanged));
public string Html
{
get { return (string)GetValue(HtmlProperty); }
set { SetValue(HtmlProperty, value); }
}
public ScrollableWebBrowser()
{
EventManager.RegisterClassHandler(typeof(ScrollViewer), ScrollViewer.ScrollChangedEvent, new ScrollChangedEventHandler(ScrollHandler));
}
static void OnHtmlChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((ScrollableWebBrowser)d).UpdateWebBrowser();
}
void UpdateWebBrowser()
{
if (this.Child == null)
this.Child = new System.Windows.Forms.WebBrowser();
System.Windows.Forms.WebBrowser browser = this.Child as System.Windows.Forms.WebBrowser;
if (browser != null)
browser.DocumentText = System.Net.WebUtility.HtmlDecode(Html);
}
private void ScrollHandler(Object sender, ScrollChangedEventArgs ea)
{
PresentationSource presentationSource = HwndSource.FromVisual(this);
if (presentationSource == null)
return;
Visual rootVisual = presentationSource.RootVisual;
if (rootVisual == null)
return;
ScrollViewer scrollViewer = (ScrollViewer)sender;
if (!scrollViewer.IsDescendantOf(rootVisual))
return;
Rect hostRect = this.TransformToAncestor(rootVisual).TransformBounds(new Rect(this.Padding.Left, this.Padding.Right, this.RenderSize.Width, this.RenderSize.Height));
Rect intersectRect = Rect.Intersect(scrollViewer.TransformToAncestor(rootVisual).TransformBounds(new Rect(0, 0, scrollViewer.ViewportWidth, scrollViewer.ViewportHeight)), hostRect);
Int32 topLeftX = 0;
Int32 topLeftY = 0;
Int32 bottomRightX = 0;
Int32 bottomRightY = 0;
if (intersectRect != Rect.Empty)
{
topLeftX = (Int32)(intersectRect.TopLeft.X - hostRect.TopLeft.X);
topLeftY = (Int32)(intersectRect.TopLeft.Y - hostRect.TopLeft.Y);
bottomRightX = (Int32)(intersectRect.BottomRight.X - hostRect.TopLeft.X);
bottomRightY = (Int32)(intersectRect.BottomRight.Y - hostRect.TopLeft.Y);
}
if (_topLeftX != topLeftX || _topLeftY != topLeftY || _bottomRightX != bottomRightX || _bottomRightY != bottomRightY)
{
_topLeftX = topLeftX;
_topLeftY = topLeftY;
_bottomRightX = bottomRightX;
_bottomRightY = bottomRightY;
SetWindowRgn(this.Handle, CreateRectRgn(_topLeftX, _topLeftY, _bottomRightX, _bottomRightY), true);
}
}
protected override void Dispose(Boolean disposing)
{
if (disposing)
{
try
{
if (!_disposed && this.Child != null)
this.Child.Dispose();
_disposed = true;
}
finally
{
base.Dispose(disposing);
}
}
}
}
回答by Sergey G.
I would recommend to use Exceed WPF ToolKit RichTextBoxwhich can bind to string representation of Xaml markup using Text
property.
For converting Html to Xaml I used HtmlToXamlConverternuget package.
HtmlToXamlConverter.ConvertHtmlToXaml(html, false)
我建议使用Exceed WPF ToolKit RichTextBox,它可以使用Text
属性绑定到 Xaml 标记的字符串表示。为了将 Html 转换为 Xaml,我使用了HtmlToXamlConverternuget 包。
HtmlToXamlConverter.ConvertHtmlToXaml(html, false)
If you want to display it as TextBlock as me here are some styles:
如果你想像我一样将它显示为 TextBlock,这里有一些样式:
Style TargetType="RichTextBox" x:Key="RichTextBoxStyle">
<Setter Property="FontFamily" Value="{StaticResource OverpassRegular}" />
<Setter Property="Foreground" Value="White" />
<Setter Property="FontWeight" Value="DemiBold" />
<Setter Property="Opacity" Value="0.95" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="CaretBrush" Value="White" />
</Style>
<Style x:Key="RichTextBoxAsTextBlock" TargetType="xctk:RichTextBox" BasedOn="{StaticResource RichTextBoxStyle}">
<Setter Property="Cursor" Value="Arrow" />
<Setter Property="SelectionBrush" Value="Transparent" />
<Setter Property="IsReadOnly" Value="True" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="Foreground">
<Setter.Value>
<SolidColorBrush Color="{DynamicResource Primary.ForegroundColor}" />
</Setter.Value>
</Setter>
<Setter Property="TextFormatter">
<Setter.Value>
<xctk:XamlFormatter />
</Setter.Value>
</Setter>
</Style>