【问题标题】:C# WebBrowser control not applying cssC# WebBrowser 控件不应用 css
【发布时间】:2019-07-30 21:06:04
【问题描述】:

我有一个正在 VS2005 中工作的项目。我添加了一个 WebBrowser 控件。我在控件中添加了一个基本的空白页面

private const string _basicHtmlForm = "<html> "
                                      + "<head> "
                                      + "<meta http-equiv='Content-Type' content='text/html; charset=utf-8'/> "
                                      + "<title>Test document</title> "
                                      + "<script type='text/javascript'> "
                                      + "function ShowAlert(message) { "
                                      + "   alert(message); "
                                      + "} "
                                      + "</script> "
                                      + "</head> "
                                      + "<body><div id='mainDiv'> "
                                      + "</div></body> "
                                      + "</html> ";

private string _defaultFont = "font-family: Arial; font-size:10pt;";

private void LoadWebForm()
{
    try 
    {
        _webBrowser.DocumentText = _basicHtmlForm;
    }
    catch(Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}  

然后通过 dom 添加各种元素(使用 _webBrowser.Document.CreateElement)。我也在加载一个css文件:

private void AddStyles()
{
    try
    {
        mshtml.HTMLDocument currentDocument = (mshtml.HTMLDocument) _webBrowser.Document.DomDocument;
        mshtml.IHTMLStyleSheet styleSheet = currentDocument.createStyleSheet("", 0);

        TextReader reader = new StreamReader(Path.Combine(Path.GetDirectoryName(Application.ExecutablePath),"basic.css"));
        string style = reader.ReadToEnd();
        styleSheet.cssText = style;
    }
    catch(Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

这是css页面内容:

body {
    background-color: #DDDDDD;
}

.categoryDiv {
    background-color: #999999;
}

.categoryTable {
    width:599px; background-color:#BBBBBB;
}

#mainDiv {
    overflow:auto; width:600px;
}

样式页面加载成功,但页面上唯一受影响的元素是页面中最初的元素(body 和 mainDiv)。我也尝试在标题部分的元素中包含 css,但它仍然只影响创建页面时存在的元素。

所以我的问题是,有没有人知道为什么 css 没有应用于页面加载后创建的元素?我也尝试在添加所有元素之前不应用 css,但结果不会改变。

【问题讨论】:

  • 我也有同样的疑惑。我一直认为以这种方式创建网页只是创建了一个陈旧/死/静态页面,并且渲染引擎停止检查样式,除非页面中的元素导致渲染器“唤醒”。但我是凭空捏造的。我刚学会在最初创建文档时将 CSS 作为第一件事添加到头部。
  • 我知道这可能根本没有帮助(这就是为什么它是一个评论),但我想从经验告诉你 C# 的 WebBrowser 组件是垃圾。看似微不足道的事情往往会让人头疼,当它不能满足您的要求时,您通常最终不得不转到底层的 ActiveX 组件……至少可以说是一团糟(大约 5 个不同的界面完全无组织,具有任意功能集)。我强烈推荐尽可能使用不同的浏览器组件,例如基于 Firefox 引擎的 GeckoFX。
  • 这里缺少一条关键信息:您正在创建的元素,以及没有样式化的元素。据推测,您将 class 属性设置为"categoryDiv"、"categoryTable" 等...但是,您的问题中没有明确说明。鉴于您所描述的结果,我更倾向于相信您的元素创建中存在一个错误,而不是任何与您的样式表创建直接相关的错误。话虽如此,您确实意识到您正在强制新样式表成为文档中的第一个(因此是最低优先级),对吧?
  • @Shog9:我怀疑你是对的。我创建了 James 项目的测试版本,并且可以很好地将样式应用于新元素(给定一些小模块)。
  • @Andre:呵呵,我也是这样做的,结果是一样的。答案很好!

标签: c# css webbrowser-control


【解决方案1】:

我对您的 AddStyles() 方法做了一些修改,它对我有用。 你从哪里调用它?我从“_webBrowser_DocumentCompleted”中调用它。

我必须指出,我在修改 DOM 后调用了 AddStyles。

private void AddStyles()
{
    try
    {
        if (_webBrowser.Document != null)
        {
            IHTMLDocument2 currentDocument = (IHTMLDocument2)_webBrowser.Document.DomDocument;

            int length = currentDocument.styleSheets.length;
            IHTMLStyleSheet styleSheet = currentDocument.createStyleSheet(@"", length + 1);
            //length = currentDocument.styleSheets.length;
            //styleSheet.addRule("body", "background-color:blue");
            TextReader reader = new StreamReader(Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "basic.css"));
            string style = reader.ReadToEnd();
            styleSheet.cssText = style;

        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

这是我的 DocumentCompleted 处理程序(我在 basic.css 中添加了一些样式进行测试):

private void _webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
  HtmlElement element = _webBrowser.Document.CreateElement("p");
  element.InnerText = "Hello World1";
  _webBrowser.Document.Body.AppendChild(element);

  HtmlElement divTag = _webBrowser.Document.CreateElement("div");
  divTag.SetAttribute("class", "categoryDiv");
  divTag.InnerHtml = "<p>Hello World2</p>";
  _webBrowser.Document.Body.AppendChild(divTag);


  HtmlElement divTag2 = _webBrowser.Document.CreateElement("div");
  divTag2.SetAttribute("id", "mainDiv2");
  divTag2.InnerHtml = "<p>Hello World3</p>";
  _webBrowser.Document.Body.AppendChild(divTag2);

  AddStyles();
}

这就是我得到的(修改了样式,使它像一个人希望的那样丑陋:D):

【讨论】:

  • 只是几个 cmets,对我来说,将此代码与 wpf webbrowser 控件一起使用,我必须将 WebControl.Document 用作 mshtml.HTMLDocument;获取文档,我在导航事件上应用了样式。谢谢
  • @LifeH2O:任务完成。 :)
【解决方案2】:

一种解决方案是在设置 DocumentText 之前检查 html 并在客户端注入 CSS。我没有设置控件 url 属性,而是通过 WebCLient 获取 HTML,然后设置 DocumentText。也许在你操作 DOM 之后设置 DocumentText(或者在你的情况下是 Document)可以让它正确地重新渲染

private const string CSS_960 = @"960.css";
private const string SCRIPT_FMT = @"<style TYPE=""text/css"">{0}</style>";
private const string HEADER_END = @"</head>";


 public void SetDocumentText(string value)
{
    this.Url = null;  // can't have both URL and DocText
    this.Navigate("About:blank");
    string css = null;
    string html = value;

    // check for known CSS file links and inject the resourced versions
    if(html.Contains(CSS_960))
    {
      css = GetEmbeddedResourceString(CSS_960);
      html = html.Insert(html.IndexOf(HEADER_END), string.Format(SCRIPT_FMT,css));
    }

    if (Document != null) { 
      Document.Write(string.Empty);
    }
    DocumentText = html;
}

【讨论】:

    【解决方案3】:

    除非您发送此链接,否则很难说。

    但通常做与样式相关的事情的最佳方法是您已经在页面中拥有 css,并且在您的 c# 代码中您只需将 id 或类添加到元素以查看样式效果。

    【讨论】:

    • 当我在页眉的样式元素中创建 css 时,我尝试在页面中包含 css,但它仍然只影响创建页面时存在的正文元素,而不影响我通过代码添加。
    • 您是否有内联样式,所以您添加的 css 可能会丢失它们的继承层次结构?
    • 最好发送一个链接,这样我就可以启动它了。很难仅仅提出问题来深入了解这一点。
    • 没有链接。它是一个 Windows 窗体内的 WebBrowser 控件。
    【解决方案4】:

    我发现生成的带有类属性的标签没有应用它们的样式。

    这是我在生成文档后完成的解决方法:

    public static class WebBrowserExtensions
    {
        public static void Redraw(this WebBrowser browser)
        {
            string temp = Path.GetTempFileName();
            File.WriteAllText(temp, browser.Document.Body.Parent.OuterHtml,
                Encoding.GetEncoding(browser.Document.Encoding));
            browser.Url = new Uri(temp);
        }
    }
    

    【讨论】:

    • 你能再解释一下吗?我有一些动态生成的 div 并且它们具有类属性 - 现在我想将 display:none 设置为这个类 - 知道我该怎么做吗?
    • @marifrahman 我帮不了你,这听起来值得question of its own
    【解决方案5】:

    我使用类似控件而不是 WebBrowser,我使用“默认”样式规则加载 HTML 页面,并更改程序中的规则。

    (DrawBack - 维护,当我需要添加规则时,我也需要在代码中更改它)

    ' ----------------------------------------------------------------------
    Public Sub mcFontOrColorsChanged(ByVal isRefresh As Boolean)  
      ' ----------------------------------------------------------------------
      ' Notify whichever is concerned:
      Dim doc As mshtml.HTMLDocument = Me.Document
      If (doc.styleSheets Is Nothing) Then Return
      If (doc.styleSheets.length = 0) Then Return
      Dim docStyleSheet As mshtml.IHTMLStyleSheet = CType(doc.styleSheets.item(0), mshtml.IHTMLStyleSheet)
      Dim docStyleRules As mshtml.HTMLStyleSheetRulesCollection = CType(docStyleSheet.rules, mshtml.HTMLStyleSheetRulesCollection)
    
      ' Note: the following is needed seperately from 'Case "BODY"
      Dim docBody As mshtml.HTMLBodyClass = CType(doc.body, mshtml.HTMLBodyClass)
      If Not (docBody Is Nothing) Then
        docBody.style.backgroundColor = colStrTextBg 
      End If
    
      Dim i As Integer
      Dim maxI As Integer = docStyleRules.length - 1
      For i = 0 To maxI
        Select Case (docStyleRules.item(i).selectorText)
          Case "BODY"
            docStyleRules.item(i).style.fontFamily = fName ' "Times New Roman" | "Verdana" | "courier new" | "comic sans ms" | "Arial"
          Case "P.myStyle1"
            docStyleRules.item(i).style.fontSize = fontSize.ToString & "pt"
          Case "TD.myStyle2" ' do nothing  
          Case ".myStyle3"
            docStyleRules.item(i).style.fontSize = fontSizePath.ToString & "pt"
            docStyleRules.item(i).style.color = colStrTextFg
            docStyleRules.item(i).style.backgroundColor = colStrTextBg
          Case Else
            Debug.WriteLine("Rule " & i.ToString & " " & docStyleRules.item(i).selectorText)
        End Select
    
      Next i
    
      If (isRefresh) Then  
        Me.myRefresh(curNode)
      End If
    
    End Sub
    

    【讨论】:

      【解决方案6】:

      可能是页面上的对象在页面加载时已经存在,因此可以应用每种样式。仅仅因为您向 DOM 树中添加了一个节点,并不意味着它可以在浏览器中对其所有属性进行操作和呈现。 上面的方法似乎使用了重新加载页面(DOM)的方法,这表明可能是这种情况。 简而言之,添加元素后刷新页面

      【讨论】:

        【解决方案7】:

        听起来好像 phq 经历过这种情况。我认为我会采用的方法是将 jquery 的引用添加到您的 html 文档中(从一开始)。

        然后在页面内部,创建一个 javascript 函数,该函数接受元素 id 和要应用的类的名称。在函数内部,使用 jquery 动态应用相关类或直接修改 css。例如,使用 jquery 的 .addClass 或 .css 函数来修改元素。

        从那里,在您的 C# 代码中,添加元素后动态调用此 javascript,如 Rick Strahl 所述:http://www.west-wind.com/Weblog/posts/493536.aspx

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-11-14
          • 2012-11-03
          • 1970-01-01
          相关资源
          最近更新 更多