我正在尝试学习MVVM并在手机应用程序中使用MVVM灯,但我对如何访问某些信息感到困惑。
我试图尽可能不使用事件背后的代码,因为这似乎不是真正的MVVM方式,但我遇到了一个我不知道该怎么做的问题。
我正在使用Google身份验证,我在每次浏览器加载后检查Naviagted事件。
public ICommand BrowserNavigated
{
get
{
return new RelayCommand<NavigationEventArgs>(e =>
{
var d = e;
var a = d;
});
}
}
但是我还需要实际的对象控件(我想访问那个页面正在吐出的html)但是我不知道如何获取它。
private void wbGoogle_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
{
var d = e;
var d2 = d;
}
在上面的代码中,我可以将“sender”转换为Web浏览器对象,但是我这样做的MVVM方式我不知道如何访问它。
我的ViewModel中是否应该为WebBrowser提供其他属性?
答案 0 :(得分:1)
在MVVM中,允许使用代码,但也许首选绑定。但是,不允许使用GUI控件/事件(硬耦合)。
可能有办法避免代码落后,但是如果你必须处理一个事件,从事件中获取数据并在你的代码中设置ViewModel的属性,那么这是一个更好的方法来做到这一点。向ViewModel添加UI代码,这显然不符合MVVM。
也许您可以创建某种EventTrigger来设置webbrowser的属性,您可以通过数据绑定来创建可在XAML中设置的可重用Trigger? (可能有很多方法可以聪明地避免代码隐藏并创建可重用的代码)
答案 1 :(得分:0)
您的ViewModel应该完全不知道View或特定控件。是否保持你的观点的代码清晰,是一个宗教问题。
如果你想保持它的清洁,我建议你尽可能使用,有许多概念,你可以这样做。
首先,您需要以某种方式设计View / ViewModel关系,ViewModel中所有与ViewModel相关的数据始终存在于ViewModel中,或者可以通过CommandParameter
传递给ViewModel。 ICommand
。在您的情况下,如果Web浏览器的页面由ViewModel控制(即可能从中设置),则ViewModel应该包含一个属性,该属性绑定到浏览器的Source
属性。如果ViewModel只需要在执行BrowserNavigated
时“知道”Uri,只需将其作为CommandParameter
传递。
其次,对于您的特定情况,您希望在引发WebBrowser的Navigated
事件时在ViewModel上执行命令。一如既往,有几种选择。我更喜欢框架附带的选项:EventTrigger
中的System.Windows.Interactivity
允许您通过绑定将任何控制事件中继到命令。
这样,可以从ViewModel设置Uri:
<WebBrowser Source="{Binding BrowserPageUri}" Name="wbGoogle">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Navigated" >
<i:InvokeCommandAction Command="{Binding BrowserNavigated}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</WebBrowser>
这样,您可以将Uri作为命令的参数处理:
<WebBrowser Name="wbGoogle">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Navigated" >
<i:InvokeCommandAction Command="{Binding BrowserNavigated}"
CommandParameter="{Binding Source, ElementName=wbGoogle}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</WebBrowser>
当然,这只允许您访问WebBrowser中的页面的Uri,而不是页面本身。如果需要绑定到页面对象本身,则需要使用附加属性扩展WebBrowser,以使Document
属性可绑定。这非常简单:
Attached Document property for WebBrowser
将此属性附加到WebBrowser后,您可以像上面的代码一样定义WebBrowser的绑定,只需使用附加属性,而不是Source
属性。
请注意,绑定到附加属性的语法是:
{Binding Path=(WebBrowserExtentions.Document)}
答案 2 :(得分:0)
MVVM可以很好地用于数据绑定,并且通过使用像MVVMLight这样的工具包,处理用户交互的事件也可以被巧妙地处理。
但有时,像WebBrowserControl
或ApplicationBar
这样的控件对此提出了挑战。它们很难或不可能与事件触发器绑定,或者具有复杂的行为。在这些情况下,如果您处理从View代码中的控件获取信息的过程并将简单消息发送到VM,则会更简单。
当然,您可以创建一个更新属性,编写附加属性或使用第三方库的事件;并且有一些案例可以保证这种方法。
在您的示例中,我个人将使用代码隐藏来处理Navigated
事件并向下发送包含VM所需内容的消息(或VM上的方法调用)去。
例如:
private void wbGoogle_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
{
var vm = (TypeOfMyViewModel) this.DataContext;
//... read your HTML, get URL etc ...
vm.WebBrowserNavigatedTo(url, html, loadTime);
}
同样,如果从您的VM引发的事件会导致View中出现很多事情,那么可以更轻松地向View发送消息或事件,并让View在代码中更新控件。
关键是保持MVVM的角色不同,例如避免ViewModel直接依赖于View。接口可以作为MVVMLight及其替代品附带的消息传递提供帮助。