2009-09-05 7 views
11

Dank this question (click me!) habe ich die Source Eigenschaft meiner WebBrowser Bindung korrekt an mein ViewModel.Gibt es eine MVVM-freundliche Möglichkeit, das WebBrowser-Steuerelement in WPF zu verwenden?

Nun möchte Ich mag zwei weitere Ziele zu erreichen:

  1. die IsEnabled Eigenschaft meiner Schaltflächen Zurück und Vorwärts Erhalten Sie richtig die WebBrowser die CanGoBack und CanGoForward Eigenschaften zu binden.
  2. Finden Sie heraus, wie Sie die GoForward() und GoBack() Methoden ohne Rückgriff auf die Code-Behind aufrufen und ohne das ViewModel über die WebBrowser wissen müssen.

Ich habe folgende (ohne Funktion) XAML-Markup im Moment:

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

Ich bin mir ziemlich sicher, dass das Problem ist, dass CanGoBack und CanGoForward nicht Abhängigkeitseigenschaften (und nicht implementieren INotifyChanged), aber ich bin nicht ganz sicher, wie ich das schaffen soll.

Fragen:

  1. Gibt es eine Möglichkeit angefügten Eigenschaften hook up (wie ich mit Source tat) oder etwas ähnliches die CanGoBack und CanGoForward Bindungen an die Arbeit?

  2. Wie schreiben die GoBackCommand und GoForwardCommand, so dass sie unabhängig von der Code-Behind und ViewModel sind und in Markup deklariert werden können?

Antwort

4

habe ich dies in meinem bindungsfähigen Web-Browser-Wrapper:

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

Bitte beachte, dass ich meinen bindungsfähigen Web-Browser als Framework erstellt, die DependencyProperties und rufen Methoden auf dem tatsächlichen Browser Element aussetzt, also kann ich Commandbindings am Set es.

Auf diese Weise können Sie die Standard-Navigationsbefehle in Ihrer Ansicht verwenden. Die verwendeten Handler sind:

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

@Botz, danke. Ich bin ein wenig verschwommen darüber, wie Sie Ihre 'FrameworkElement' Klasse tatsächlich einrichten. Ich nehme an, Sie haben ein Feld 'webBrowser', aber wie bekommen Sie es eigentlich angezeigt? Ich dachte, ich müsste ein "UserControl" erstellen und den "WebBrowser" in ein "Grid" auf dem Steuerelement platzieren. Wie gehst du mit einer Klasse um, die 'FrameworkElement' erbt? Vielen Dank. – devuxer

+0

Sie brauchen eigentlich kein UserControl, ein FrameworkElement ist in Ordnung, solange Sie es richtig eingerichtet haben. Meine Implementierung ist vielleicht nicht die beste, aber wenn Sie einen Blick darauf werfen wollen, finden Sie das Steuerelement hier: http://pastebin.com/m492dbd3f (Wenn Sie sich über BrowserViewModel wundern, ist es das ViewModel, an das die Eigenschaften des Steuerelements gebunden sind , ich bin sicher, dass Sie bereits Ihr eigenes ViewModel haben) – Botz3000

+0

// btw Wenn Sie von FrameworkElement ableiten, können Sie AddVisualChild und AddLogicalChild aufrufen, um den WebBrowser oder irgendetwas anderes darin wirklich zu setzen – Botz3000

0

Ihre Frage scheint, dass, um zu implizieren, richtig ein MVVM Muster zu implementieren, Sie sind nicht erlaubt jeder Code-behind zu haben. Aber vielleicht fügt das Hinzufügen eines Code-Behinds zu Ihrer Ansicht es viel einfacher, es mit Ihrem Ansichtsmodell zu verbinden. Sie können der Ansicht Abhängigkeitseigenschaften hinzufügen und sie auf INotifyPropertyChanged Ereignisse überwachen lassen.

4

Für jeden, der auf diese Frage stößt und eine komplette Lösung wünscht, hier ist es. Es kombiniert alle Vorschläge in diesem Thread und den verknüpften Threads (und anderen, auf die diese verweisen).

XAML: http://pastebin.com/aED9pvW8

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

Beispiel XAML Nutzung: http://pastebin.com/JpuNrFq8

Hinweis: Das Beispiel geht davon aus Ihrer Sicht auf ein Ansichtsmodell bindet, die die Quell-URL an den Browser liefert . Eine sehr rudimentäre Navigationsleiste mit Schaltflächen zum Zurück-, Vorwärts- und Aktualisieren sowie der Adressleiste dient nur zur Demonstration.

Genießen. Ich habe den Ablauf für diese Pastebins auf nie eingestellt, also sollten sie so lange verfügbar sein, wie Pastebin existiert.

+0

Sehr schön, danke. Ich habe mich gefragt, wofür der _SkipSourceChange da ist? – Peter