【问题标题】:Is there an MVVM-friendly way to use the WebBrowser control in WPF?是否有一种 MVVM 友好的方式来使用 WPF 中的 WebBrowser 控件?
【发布时间】:2010-11-25 22:21:51
【问题描述】:

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

现在我想实现另外两个目标:

  1. 获取我的后退和前进按钮的IsEnabled 属性以正确绑定到WebBrowserCanGoBackCanGoForward 属性。
  2. 弄清楚如何调用 GoForward()GoBack() 方法,而无需借助代码隐藏,也无需 ViewModel 知道 WebBrowser

我目前有以下(非工作)XAML 标记:

<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;" />

我很确定问题在于 CanGoBackCanGoForward 不是依赖属性(并且不实现 INotifyChanged),但我不太确定如何解决这个问题。

问题:

  1. 是否有任何方法可以连接附加属性(就像我对 Source 所做的那样)或类似的方法来使 CanGoBackCanGoForward 绑定工作?

  2. 如何编写GoBackCommandGoForwardCommand,使其独立于代码隐藏和ViewModel 并可以在标记中声明?

【问题讨论】:

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


    【解决方案1】:

    对于遇到此问题并想要完整解决方案的任何人,这里就是。它结合了此主题中提出的所有建议以及链接的主题(以及链接到的其他主题)。

    XAML: http://pastebin.com/aED9pvW8

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

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

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

    享受。我已将这些 pastebin 的过期时间设置为从不,因此只要 pastebin 存在,它们就应该可用。

    【讨论】:

    • 非常好,谢谢。我想知道 _SkipSourceChange 有什么用?
    【解决方案2】:

    您的问题似乎暗示,为了正确实现 MVVM 模式,您不允许有任何代码隐藏。但是也许在你的视图中添加一些代码隐藏会让你更容易将它与你的视图模型挂钩。你可以给视图添加依赖属性,让它监听INotifyPropertyChanged事件。

    【讨论】:

      【解决方案3】:

      我在可绑定的网络浏览器包装器中使用了这个:

          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);
      }
      

      【讨论】:

      • @Botz,谢谢。我对您实际设置FrameworkElement 课程的方式有点模糊。我假设你有一个字段webBrowser,但你如何真正让它显示?我在想我需要构建一个UserControl 并实际将WebBrowser 放在控件上的Grid 中。你如何使用继承FrameworkElement 的类来处理这个问题?谢谢。
      • 您实际上并不需要 UserControl,只要您正确设置它,FrameworkElement 就可以了。我的实现可能不是最好的,但如果你想看看,可以在这里找到控件:pastebin.com/m492dbd3f(如果你想知道 BrowserViewModel,它是控件的属性实际上绑定到的 ViewModel,我相信你不过已经有了自己的 ViewModel)
      • // 顺便说一句,如果您从 FrameworkElement 派生,您可以调用 AddVisualChild 和 AddLogicalChild 将 WebBrowser 或其他任何内容实际放入其中
      • @Botz,啊,很好,谢谢。它现在正在我的窗口内工作。我只需要一个关于如何绑定到 NavigationCommands.BrowseBack 的线索。到目前为止,我已经尝试过 Command="{Binding ElementName=_instructionsWebBrowser, Path=NavigationCommands.BrowseForward}"Command="{Binding NavigationCommands.BrowseForward}" 并且没有运气。再次感谢!
      • @Botz,我也尝试过简单的Command="NavigationCommands.BrowseForward",但这也不起作用。
      猜你喜欢
      • 2011-08-28
      • 2011-12-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-02
      • 1970-01-01
      • 2015-06-18
      • 2011-06-10
      相关资源
      最近更新 更多