首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C# FlowDocument到FlowDocument的转换

C# FlowDocument到FlowDocument的转换
EN

Stack Overflow用户
提问于 2011-06-04 11:30:52
回答 3查看 9.9K关注 0票数 9

基本上,我有一个RichTextBox,我想把它的格式化内容转换成HTML,这样它就可以作为电子邮件发送。

我目前使用的方法根本不提供任何格式:

代码语言:javascript
复制
string message = new TextRange(messageTextBox.Document.ContentStart,
                               messageTextBox.Document.ContentEnd).Text;

所以我搜索了一下,发现已经有5年多的历史了,在评论中,一位微软用户评论说它不再受支持-- "This sample has been removed from our sample set and is no longer supported",它生成的HTML格式比现代的HTML或XHTML更好。

有人能告诉我如何将格式的RichTextBox内容转换为RichTextBox吗?

(因此,当电子邮件发送时,收件人会看到带有格式的电子邮件)

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-06-04 17:46:06

一般技术是使用XamlWriterFlowDocument内容转换为XML流,然后使用XSLT转换将XML转换为HTML。这不是一个很好的答案,但这是因为对于任何给定的FlowDocument,都有大量可能的HTML表示。

例如,这种转换将每个顶级Section转换为div,将每个Paragraph转换为p,将每个Run转换为span,后者的类告诉您它是否为斜体、粗体或下划线,或上述任何组合。它对于我编写它的目的是有用的,但是把它称为有损转换是一种低估:

代码语言:javascript
复制
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
    version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt"
    exclude-result-prefixes="msxsl x">

  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>

  <xsl:template match="x:Section[not(parent::x:Section)]">
    <div>
      <xsl:apply-templates select="node()"/>
    </div>
  </xsl:template>

  <xsl:template match="x:Section">
    <xsl:apply-templates select="node()"/>
  </xsl:template>

  <xsl:template match="x:Paragraph">
    <p>
      <xsl:apply-templates select="node()"/>
    </p>
  </xsl:template>

  <xsl:template match="x:Run">
    <xsl:variable name="class">
      <xsl:if test="@FontStyle='Italic'">
        <xsl:text>i </xsl:text>
      </xsl:if>
      <xsl:if test="@FontWeight='Bold'">
        <xsl:text>b </xsl:text>
      </xsl:if>
      <xsl:if test="contains(@TextDecorations, 'Underline')">
        <xsl:text>u </xsl:text>
      </xsl:if>
    </xsl:variable>
    <span>
      <xsl:if test="normalize-space($class) != ''">
        <xsl:attribute name="class">
          <xsl:value-of select="normalize-space($class)"/>
        </xsl:attribute>
      </xsl:if>
      <xsl:value-of select="text()"/>
    </span>
  </xsl:template>

</xsl:stylesheet>

下面是我编写的一个值转换器--注意,为了使用值转换器,您还必须破解并实现一个RichTextBox版本,该版本将内容公开为依赖项属性。真的,整个项目都很痛苦。

代码语言:javascript
复制
public class FlowDocumentToHtmlConverter : IValueConverter
{
    private static XslCompiledTransform ToHtmlTransform;
    private static XslCompiledTransform ToXamlTransform;

    public FlowDocumentToHtmlConverter()
    {
        if (ToHtmlTransform == null)
        {
            ToHtmlTransform = LoadTransformResource("Converters/FlowDocumentToXhtml.xslt");
        }
        if (ToXamlTransform == null)
        {
            ToXamlTransform = LoadTransformResource("Converters/XhtmlToFlowDocument.xslt");
        }
    }
    private static XslCompiledTransform LoadTransformResource(string path)
    {
        Uri uri = new Uri(path, UriKind.Relative);
        XmlReader xr = XmlReader.Create(Application.GetResourceStream(uri).Stream);
        XslCompiledTransform xslt = new XslCompiledTransform();
        xslt.Load(xr);
        return xslt;
    }

    #region IValueConverter Members

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (!(value is FlowDocument))
        {
            return null;
        }
        if (targetType == typeof(FlowDocument))
        {
            return value;
        }

        if (targetType != typeof(string))
        {
            throw new InvalidOperationException(
                "FlowDocumentToHtmlConverter can only convert back from a FlowDocument to a string.");
        }

        FlowDocument d = (FlowDocument)value;

        using (MemoryStream ms = new MemoryStream())
        {
            // write XAML out to a MemoryStream
            TextRange tr = new TextRange(
                d.ContentStart,
                d.ContentEnd);
            tr.Save(ms, DataFormats.Xaml);
            ms.Seek(0, SeekOrigin.Begin);

            // transform the contents of the MemoryStream to HTML
            StringBuilder sb = new StringBuilder();
            using (StringWriter sw = new StringWriter(sb))
            {
                XmlWriterSettings xws = new XmlWriterSettings();
                xws.OmitXmlDeclaration = true;
                XmlReader xr = XmlReader.Create(ms);
                XmlWriter xw = XmlWriter.Create(sw, xws);
                ToHtmlTransform.Transform(xr, xw);
            }
            return sb.ToString();
        }
    }

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value == null)
        {
            return new FlowDocument();
        }
        if (value is FlowDocument)
        {
            return value;
        }
        if (targetType != typeof(FlowDocument))
        {
            throw new InvalidOperationException(
                "FlowDocumentToHtmlConverter can only convert to a FlowDocument.");
        }
        if (!(value is string))
        {
            throw new InvalidOperationException(
                "FlowDocumentToHtmlConverter can only convert from a string or FlowDocument.");
        }

        string s = (string)value;

        FlowDocument d;

        using (MemoryStream ms = new MemoryStream())
        using (StringReader sr = new StringReader(s))
        {
            XmlWriterSettings xws = new XmlWriterSettings();
            xws.OmitXmlDeclaration = true;
            using (XmlReader xr = XmlReader.Create(sr))
            using (XmlWriter xw = XmlWriter.Create(ms, xws))
            {
                ToXamlTransform.Transform(xr, xw);
            }
            ms.Seek(0, SeekOrigin.Begin);

            d = XamlReader.Load(ms) as FlowDocument;
        }
        XamlWriter.Save(d, Console.Out);
        return d;
    }

    #endregion
}
票数 14
EN

Stack Overflow用户

发布于 2020-02-28 17:17:54

我认为以上XSLT工作表的扩展版本可能会有所帮助。不完美,但稍微全面一些。引用此答案的另一个答案的扩展。

代码语言:javascript
复制
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
    version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt"
    exclude-result-prefixes="msxsl x">

  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>

  <!--<xsl:template match="x:Section[not(parent::x:Section)]">
    <div>
      <xsl:apply-templates select="node()"/>
    </div>
  </xsl:template>-->

  <xsl:template match="x:Section[not(parent::x:Section)]">
    <xsl:variable name="style">
      <xsl:if test="@FontStyle='Italic'">
        <xsl:text>font-style:italic;</xsl:text>
      </xsl:if>
      <xsl:if test="@FontWeight='Bold'">
        <xsl:text>font-weight:bold;</xsl:text>
      </xsl:if>
      <xsl:if test="contains(@TextDecorations, 'Underline')">
        <xsl:text>text-decoration:underline;</xsl:text>
      </xsl:if>
      <xsl:if test="@FontSize != ''">
        <xsl:text>font-size:</xsl:text>
        <xsl:value-of select="@FontSize" />
        <xsl:text>pt;</xsl:text>
      </xsl:if>
      <xsl:if test="@FontFamily != ''">
        <xsl:text>font-family:</xsl:text>
        <xsl:value-of select="@FontFamily" />
        <xsl:text>;</xsl:text>
      </xsl:if>
      <xsl:if test="@Foreground != ''">
        <xsl:text>color:</xsl:text>
        <xsl:value-of select="concat(substring(@Foreground, 1, 1), substring(@Foreground, 4))" />
        <xsl:text>;</xsl:text>
      </xsl:if>
      <xsl:if test="@Foreground-Color != ''">
        <xsl:text>color:</xsl:text>
        <xsl:value-of select="@Foreground-Color"/>
        <xsl:text>;</xsl:text>
      </xsl:if>
    </xsl:variable>
    <div>
      <xsl:if test="normalize-space($style) != ''">
        <xsl:attribute name="style">
          <xsl:value-of select="normalize-space($style)"/>
        </xsl:attribute>
      </xsl:if>
      <xsl:value-of select="text()"/>
      <xsl:apply-templates select="node()"/>
    </div>
  </xsl:template>


  <xsl:template match="x:Section">
    <xsl:apply-templates select="node()"/>
  </xsl:template>

  <xsl:template match="x:Paragraph">
    <xsl:variable name="style">
      <xsl:if test="@FontStyle='Italic'">
        <xsl:text>font-style:italic;</xsl:text>
      </xsl:if>
      <xsl:if test="@FontWeight='Bold'">
        <xsl:text>font-weight:bold;</xsl:text>
      </xsl:if>
      <xsl:if test="contains(@TextDecorations, 'Underline')">
        <xsl:text>text-decoration:underline;</xsl:text>
      </xsl:if>
      <xsl:if test="@FontSize != ''">
        <xsl:text>font-size:</xsl:text>
        <xsl:value-of select="@FontSize" />
        <xsl:text>pt;</xsl:text>
      </xsl:if>
      <xsl:if test="@FontFamily != ''">
        <xsl:text>font-family:</xsl:text>
        <xsl:value-of select="@FontFamily" />
        <xsl:text>;</xsl:text>
      </xsl:if>
      <xsl:if test="@Foreground != ''">
        <xsl:text>color:</xsl:text>
        <xsl:value-of select="concat(substring(@Foreground, 1, 1), substring(@Foreground, 4))" />
        <xsl:text>;</xsl:text>
      </xsl:if>
      <xsl:if test="@Foreground-Color != ''">
        <xsl:text>color:</xsl:text>
        <xsl:value-of select="@Foreground-Color"/>
        <xsl:text>;</xsl:text>
      </xsl:if>
    </xsl:variable>
    <p>
      <xsl:if test="normalize-space($style) != ''">
        <xsl:attribute name="style">
          <xsl:value-of select="normalize-space($style)"/>
        </xsl:attribute>
      </xsl:if>
      <xsl:value-of select="text()"/>
      <xsl:apply-templates select="node()"/>
    </p>
  </xsl:template>

  <xsl:template match="x:Span">
    <xsl:variable name="style">
      <xsl:if test="@FontStyle='Italic'">
        <xsl:text>font-style:italic;</xsl:text>
      </xsl:if>
      <xsl:if test="@FontWeight='Bold'">
        <xsl:text>font-weight:bold;</xsl:text>
      </xsl:if>
      <xsl:if test="contains(@TextDecorations, 'Underline')">
        <xsl:text>text-decoration:underline;</xsl:text>
      </xsl:if>
      <xsl:if test="@FontSize != ''">
        <xsl:text>font-size:</xsl:text>
        <xsl:value-of select="@FontSize" />
        <xsl:text>pt;</xsl:text>
      </xsl:if>
      <xsl:if test="@FontFamily != ''">
        <xsl:text>font-family:</xsl:text>
        <xsl:value-of select="@FontFamily" />
        <xsl:text>;</xsl:text>
      </xsl:if>
      <xsl:if test="@Foreground != ''">
        <xsl:text>color:</xsl:text>
        <xsl:value-of select="concat(substring(@Foreground, 1, 1), substring(@Foreground, 4))" />
        <xsl:text>;</xsl:text>
      </xsl:if>
      <xsl:if test="@Foreground-Color != ''">
        <xsl:text>color:</xsl:text>
        <xsl:value-of select="@Foreground-Color"/>
        <xsl:text>;</xsl:text>
      </xsl:if>
    </xsl:variable>
    <span>
      <xsl:if test="normalize-space($style) != ''">
        <xsl:attribute name="style">
          <xsl:value-of select="normalize-space($style)"/>
        </xsl:attribute>
      </xsl:if>
      <xsl:value-of select="text()"/>
      <xsl:apply-templates select="node()"/>
    </span>
  </xsl:template>


  <xsl:template match="x:Run">
    <xsl:variable name="style">
      <xsl:if test="@FontStyle='Italic'">
        <xsl:text>font-style:italic;</xsl:text>
      </xsl:if>
      <xsl:if test="@FontWeight='Bold'">
        <xsl:text>font-weight:bold;</xsl:text>
      </xsl:if>
      <xsl:if test="contains(@TextDecorations, 'Underline')">
        <xsl:text>text-decoration:underline;</xsl:text>
      </xsl:if>
      <xsl:if test="@FontSize != ''">
        <xsl:text>font-size:</xsl:text>
        <xsl:value-of select="@FontSize" />
        <xsl:text>pt;</xsl:text>
      </xsl:if>
      <xsl:if test="@FontFamily != ''">
        <xsl:text>font-family:</xsl:text>
        <xsl:value-of select="@FontFamily" />
        <xsl:text>;</xsl:text>
      </xsl:if>
      <xsl:if test="@Foreground != ''">
        <xsl:text>color:</xsl:text>
        <xsl:value-of select="concat(substring(@Foreground, 1, 1), substring(@Foreground, 4))" />
        <xsl:text>;</xsl:text>
      </xsl:if>
      <xsl:if test="@Foreground-Color != ''">
        <xsl:text>color:</xsl:text>
        <xsl:value-of select="@Foreground-Color"/>
        <xsl:text>;</xsl:text>
      </xsl:if>
    </xsl:variable>
    <span>
      <xsl:if test="normalize-space($style) != ''">
        <xsl:attribute name="style">
          <xsl:value-of select="normalize-space($style)"/>
        </xsl:attribute>
      </xsl:if>
      <xsl:value-of select="text()"/>
      <xsl:apply-templates select="node()"/>
    </span>
  </xsl:template>
</xsl:stylesheet>
票数 1
EN

Stack Overflow用户

发布于 2021-04-21 06:20:46

对于那些正在为.Net核心(APS.Net核心)寻找解决方案的人来说,nuget MarkupConverter为我做了一个窍门。添加依赖关系引用

代码语言:javascript
复制
<PackageReference Include="MarkupConverter" Version="1.0.6" />

那就用它

代码语言:javascript
复制
MarkupConverter.MarkupConverter markupConverter = new MarkupConverter.MarkupConverter();
try
{
  message = markupConverter.ConvertXamlToHtml(message);
}
catch (Exception ex)
{
  _logger.LogError(ex, $"Failed to parse flowdocument");
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6236483

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档