是否有一种MVVM友好的方式在WPF中使用WebBrowser控件?

时间:2009-09-05 20:20:25

标签: wpf data-binding xaml mvvm webbrowser-control

感谢this question (click me!),我的Source属性的WebBrowser属性正确绑定到我的ViewModel。

现在我想再实现两个目标:

  1. 获取“后退”和“前进”按钮的IsEnabled属性,以正确绑定CanGoBack的{​​{1}}和CanGoForward属性。
  2. 了解如何调用WebBrowserGoForward()方法,而无需使用代码隐藏且ViewModel不必了解GoBack()
  3. 我现在有以下(非工作)XAML标记:

    WebBrowser

    我很确定问题是<WebBrowser x:Name="_instructionsWebBrowser" x:FieldModifier="private" clwm:WebBrowserUtility.AttachedSource="{Binding InstructionsSource}" /> <Button Style="{StaticResource Button_Style}" Grid.Column="2" IsEnabled="{Binding ElementName=_instructionsWebBrowser, Path=CanGoBack}" Command="{Binding GoBackCommand}" Content="&lt; Back" /> <Button Style="{StaticResource Button_Style}" Grid.Column="4" IsEnabled="{Binding ElementName=_instructionsWebBrowser, Path=CanGoForward}" Command="{Binding GoForwardCommand}" Content="Forward &gt;" /> CanGoBack不是依赖属性(并且没有实现CanGoForward),但我不太确定如何获取在那附近。

    问题:

    1. 有没有办法连接附加的属性(就像我使用INotifyChanged)或类似的东西来使SourceCanGoBack绑定起作用?

    2. 如何编写CanGoForwardGoBackCommand以便它们独立于代码隐藏和ViewModel并且可以在标记中声明?

3 个答案:

答案 0 :(得分:4)

我在可绑定的webbrowser包装器中使用了它:

    CommandBindings.Add(new CommandBinding(NavigationCommands.BrowseBack, BrowseBack, CanBrowseBack));
    CommandBindings.Add(new CommandBinding(NavigationCommands.BrowseForward, BrowseForward, CanBrowseForward));
    CommandBindings.Add(new CommandBinding(NavigationCommands.BrowseHome, GoHome, TrueCanExecute));
    CommandBindings.Add(new CommandBinding(NavigationCommands.Refresh, Refresh, TrueCanExecute));
    CommandBindings.Add(new CommandBinding(NavigationCommands.BrowseStop, Stop, TrueCanExecute));

请注意,我创建了我的可绑定webbrowser作为FrameworkElement,它公开DependencyProperties并在实际的浏览器元素上调用方法,所以我可以在其上设置CommandBindings。

这样,您可以在视图中使用默认的NavigationCommands。 使用过的处理程序是:

private void CanBrowseBack(object sender, CanExecuteRoutedEventArgs e) {
    e.CanExecute = webBrowser.CanGoBack;
}

private void BrowseBack(object sender, ExecutedRoutedEventArgs e) {
    webBrowser.GoBack();
}

private void CanBrowseForward(object sender, CanExecuteRoutedEventArgs e) {
    e.CanExecute = webBrowser.CanGoForward;
}

private void BrowseForward(object sender, ExecutedRoutedEventArgs e) {
    webBrowser.GoForward();
}

private void TrueCanExecute(object sender, CanExecuteRoutedEventArgs e) { e.CanExecute = true; }

private void Refresh(object sender, ExecutedRoutedEventArgs e) {
    try { webBrowser.Refresh(); }
    catch (Exception ex) { PmsLog.LogException(ex, true); }
}

private void Stop(object sender, ExecutedRoutedEventArgs e) {
    mshtml.IHTMLDocument2 doc = WebBrowser.Document as mshtml.IHTMLDocument2;
    if (doc != null)
        doc.execCommand("Stop", true, null);
}
private void GoHome(object sender, ExecutedRoutedEventArgs e) {
    Source = new Uri(Home);
}

答案 1 :(得分:4)

对于遇到这个问题而想要一个完整解决方案的人来说,就是这样。它结合了该线程和链接线程(以及其他链接线程)中提出的所有建议。

XAML: http://pastebin.com/aED9pvW8

C#类: http://pastebin.com/n6cW9ZBB

示例XAML用法: http://pastebin.com/JpuNrFq8

注意:该示例假定您的视图绑定到提供浏览器源URL的ViewModel。一个非常基本的导航栏,带有后退,前进和刷新按钮以及地址栏,仅供演示。

享受。我已经将那些pastebin的到期时间设置为never,因此只要存在pastebin,它们就应该可用。

答案 2 :(得分:0)

您的问题似乎暗示,为了正确实现MVVM模式,您不能拥有任何代码隐藏。但是,在您的视图中添加一些代码隐藏可能会更容易将其与视图模型联系起来。您可以向视图添加依赖项属性,并让它监听INotifyPropertyChanged个事件。