如何通过 MVVM 在 WPF WebBrowser 控件上使用 Javascript
Posted
技术标签:
【中文标题】如何通过 MVVM 在 WPF WebBrowser 控件上使用 Javascript【英文标题】:How to use Javascript on a WPF WebBrowser Control via MVVM 【发布时间】:2011-11-02 23:56:51 【问题描述】:我在 WPF4 上使用 MVVM 模式,尽管我对这两种模式都是新手。我正在寻找一个很好的解决方案来使用可以接收 javascript 命令并与 ViewModel 通信的 WebBrowser 控件。它需要以下内容:
-
能够从 Javascript 表单中收集值并将其返回给 ViewModel
使用Javascript判断ReadyState之前
运行 Javascript 命令(设置表单值、将表单值用于逻辑步骤、提交表单)一些会在多个页面加载时发生
正在处理的网站不受我的控制,无法编辑或更新。它大量使用 ActiveX,并且不接受非 IE 浏览器(Awesomium 将不起作用),因此标准的 WPF WebBrowser 控件可能是唯一的选择。
This question 提供了一种将浏览器控件的源与附加属性绑定的解决方案。我认为这可以适用于使用导航方法发送 javascript,但我不确定如何将值返回到 Viewmodel。这是我需要克服的主要障碍。
重度编辑 - 问题的浏览量很低,没有答案,完全改写了
【问题讨论】:
重新成为你的旗帜:这超出了模组的能力。可以咨询Meta Stack Overflow。 奖励赏金的方式确实有点奇怪,您可能想将此作为 MSO 上的一个可能的错误提出。我不知道为什么它在仅仅六天后就被授予了。 Known (and fixed) bug。开发人员应该能够撤消赏金或类似的事情。 【参考方案1】:如果您与网站开发人员合作为您的应用程序创建解决方案,那么您将使用ObjectForScripting
在 JavaScript 和应用程序之间进行通信。有一篇很好的文章here,还有一个可能有帮助的问题here。
但是,据我了解,该网站是一个任意第三方网站,与您的应用程序没有任何关联,您希望自动填写一些表单值并在您的代码中提交表单。
为此,您可以处理 WebBrowser 的 LoadCompleted
事件。当加载的文档readyState
更改为已完成时调用此方法。因此,您可以将此事件用作挂钩,然后设置/读取文档表单值。请注意,您需要在项目中添加对 Microsoft mshtml
的引用。
以下是一个 MVVM 样式 (PRISM) 命令,它允许事件使用行为直接绑定到 ViewModel
。这相当于在代码隐藏中注册一个事件处理程序。
public ICommand LoadCompleted
get
return new EventToCommandWithSender<NavigationEventArgs>(
(s,e) =>
WebBrowser browser = (WebBrowser) sender;
// false if nested frame
if (e.IsNavigationInitiator)
mshtml.IHTMLDocument2 doc = (mshtml.IHTMLDocument2)browser.Document;
// always completed
var readyState = doc.readyState;
// populate form
var name = doc.body.document.getElementById("username");
name.value = "@TheCodeKing";
// submit form
var submit = doc.body.document.getElementById("submit");
submit.Click();
);
很遗憾,NavigationEventArgs
没有提供访问 HTML 文档或请求数据的方法。它确实包含一个WebRequest
属性,但这尚未实现,并且始终为空。在我的示例中,我假设了一个自定义的 EventToCommandWithSender
类,它在事件触发时提供发送者以及事件 ARG,但要获得对发送者的访问权限取决于您自己的实现。
【讨论】:
我可以看到如何使用它来获取值,但也可以使用此方法设置值,并通过javascript提交表单? 其实我对此有一个疑问,我是否必须使用附加行为将命令绑定到导航事件,或者有直接的方法吗? 是的,我认为您可以使用文档加载事件来调用 JavaScript 并发布表单。我还没试过。您将对事件使用附加行为。我认为 Prism 提供了另一种选择,但我已经有一段时间没有使用它了。 在 javascript 完成执行之前,html 渲染完成时不会发生文档加载事件吗?我将研究棱镜,看看它是否可以做到这一点。您的回答很有帮助,但我认为它并不完整。 WebBrowser 控件 DocumentLoaded 事件在控件完成下载内容并呈现页面时发生。它为您的问题的第 2 部分和第 3 部分提供了一个钩子。回到电脑前我会澄清(当你说 ReadyState 时,你是什么意思?)。 Prism 是一个用于构建 WPF 应用程序以分离关注点的框架(与客户端代码无关)。我不确定你是否在使用它。【参考方案2】:我不知道为什么我以前从未想过,但解决方案似乎很简单。
不要在视图上使用<WebBrowser
> 控件,而是使用<ContentControl>
并将其内容绑定到 ViewModel 中的 WebBrowser 属性。在 ViewModel 的构造函数中创建 WebBrowser,然后您可以将浏览器的导航事件(或 documentloaded)注册到 ViewModel 中的事件中。
来自 ViewModel 的完全浏览器控制!您甚至可以捕获用户事件,因为他们为导航页面所做的任何事情都将被捕获到您的 ViewModel 的导航事件中。
【讨论】:
难以置信的解决方案! 很好,这帮助我解决了一个有点相关的问题,即必须为可绑定的 Source 和 ObjectForScripting 属性编写 DependencyProperties,其中脚本对象似乎无论如何都绑定得太晚了。现在我只有一个简单的 WebBrowser 构造函数,并且可以转储整个辅助类。以上是关于如何通过 MVVM 在 WPF WebBrowser 控件上使用 Javascript的主要内容,如果未能解决你的问题,请参考以下文章
如何在 MVVM 模式中从页面导航到 WPF 中的页面?没有棱镜的概念[重复]