我有一个实现WPF WebBrowser控件的应用程序。它加载一个包含一些JS函数的页面,这些函数必须从我的应用程序调用,可能来自其他线程。我希望坚持使用MVVM模式并保留用于解析模型中函数返回的代码。在WebBrowser对象上调用InvokeScript方法应该在Dispatcher线程上进行(因此在视图中),因为它是一个UI元素。
我目前为完成这项工作所采取的步骤(大致是假的):
- subscribe to the LoadCompleted event of the browser (view)
- set the browser source (model -> viewmodel -> view)
- catch the LoadCompleted event (view -> viewmodel -> model)
- some logic (model)
- invoke script (model -> viewmodel -> view)
- get script result (view -> viewmodel -> model)
- some logic (model)
这导致模型和视图之间的相当一些来回通信(通过视图模型)。由于我不熟悉WPF(或MVVM),我想知道是否有一种更简洁的方式来完成这项任务(并且我的意思是:更少的模型,视图模型和视图之间的调用和事件)。 / p>
答案 0 :(得分:0)
我知道这不是你问题的答案,但它可能在将来对你有所帮助。看看名为CefSharp的组件。这是Chrome Embedded Framework的c#包装器。它非常适合MVVM,它是开源的,免费的,并且开发起来相当容易。我最近从另一个Chrome包装器(Awesomium)转移到它,非常满意。
CefSharp允许您从页面调用js函数,甚至支持对这些调用的异步/等待。
答案 1 :(得分:0)
MVVM的主要观点是将接口(特定于平台:windows \ android \ ios \ windows phone等)与其他所有接口分开,以便您可以在不同平台上重用逻辑(viewmodel \ model)。所以很明显你不能直接从viewmodel调用InvokeScript - 但不是因为调度程序。您可以抽象出调度程序(for example),因为在某些情况下,您需要在视图模型中使用它。所以通常当viewmodel需要对视图执行操作时 - 使用事件(或只是委托):
public class MyViewModel
{
public Func<string, object> InvokeScript { get; set; }
public Func<string, Task<object>> InvokeScriptAsync { get; set; }
public async void Something() {
var result = await InvokeScriptAsync("my script");
// do something
}
}
在你看来:
public class MyView {
private void OnViewModelChanged(MyViewModel vm) {
vm.InvokeScript = text => Dispatcher.Invoke(() => browser.InvokeScript(text));
vm.InvokeScriptAsync = text => browser.InvokeScriptAsync(text); // for example
}
}