2009-09-05 5 views
11

Grâce à this question (click me!), j'ai la propriété Source de ma WebBrowser qui se lie correctement à mon ViewModel.Existe-t-il une façon conviviale MVVM d'utiliser le contrôle WebBrowser dans WPF?

Maintenant, je voudrais réaliser deux objectifs:

  1. obtenir la propriété IsEnabled de mes boutons Précédent et Suivant pour lier correctement les propriétés CanGoBack et CanGoForward du WebBrowser.
  2. Découvrez comment appeler les méthodes GoForward() et GoBack() sans recourir au code-behind et sans que le ViewModel ait à connaître le WebBrowser.

Je donne les résultats suivants (non-travail) balisage XAML au 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;" /> 

Je suis sûr que le problème est que CanGoBack et CanGoForward ne sont pas des propriétés de dépendance (et ne mettent pas en œuvre INotifyChanged), mais je ne suis pas sûr de savoir comment contourner cela.

Questions:

  1. Est-il possible de brancher des propriétés attachées (comme je l'ai fait avec Source) ou quelque chose de similaire pour obtenir les liaisons CanGoBack et CanGoForward au travail?

  2. Comment écrire les GoBackCommand et GoForwardCommand afin qu'ils soient indépendants du code-behind et ViewModel et peuvent être déclarés dans le balisage?

Répondre

4

J'ai utilisé dans mon bindable emballage 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)); 

Notez que j'ai créé mon bindable webbrowser comme FrameworkElement qui expose DependencyProperties et appelle des méthodes sur l'élément de navigateur réel, donc je peux mettre CommandBindings sur il. De cette façon, vous pouvez utiliser les Commandes de navigation par défaut dans votre vue. Les gestionnaires sont utilisés:

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, merci. Je suis un peu flou sur la façon dont vous configurez votre classe 'FrameworkElement'. Je suppose que vous avez un champ 'webBrowser', mais comment l'afficher? Je pensais que je devrais construire un 'UserControl' et placer réellement' WebBrowser' dans, disons, un 'Grid' sur le contrôle. Comment gérez-vous cela avec une classe qui hérite de 'FrameworkElement'? Merci. – devuxer

+0

Vous n'avez pas vraiment besoin d'un UserControl, un FrameworkElement est parfait tant que vous le configurez correctement. Mon implémentation n'est peut-être pas la meilleure, mais si vous voulez jeter un oeil, le contrôle peut être trouvé ici: http://pastebin.com/m492dbd3f (si vous vous posez des questions sur BrowserViewModel, c'est le ViewModel, les propriétés du contrôle sont en fait liées à , je suis sûr que vous avez déjà votre propre ViewModel si) – Botz3000

+0

// btw Si vous dérivez de FrameworkElement, vous pouvez appeler AddVisualChild et AddLogicalChild pour mettre réellement le WebBrowser ou toute autre chose dedans – Botz3000

0

Votre question semble impliquer que pour mettre en œuvre correctement un modèle MVVM vous n'êtes pas autorisé à avoir un code-behind. Mais peut-être que l'ajout de code-behind à votre vue rendra plus facile le raccordement avec votre view-model. Vous pouvez ajouter des propriétés de dépendance à la vue et l'écouter pour les événements INotifyPropertyChanged.

4

Pour tous ceux qui rencontrent cette question et veulent une solution complète, la voici. Il combine toutes les suggestions faites dans ce fil de discussion et les fils liés (et d'autres ceux liés à).

XAML: http://pastebin.com/aED9pvW8

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

Exemple d'utilisation XAML: http://pastebin.com/JpuNrFq8

Note: L'exemple suppose que votre vue se lie à une ViewModel qui fournit l'URL source au navigateur . Une barre de navigation très rudimentaire avec des boutons de retour, d'avance et d'actualisation et une barre d'adresse est fournie juste pour la démonstration.

Profitez-en. J'ai placé l'expiration sur ces pastebin à jamais, ainsi ils devraient être disponibles aussi longtemps que pastebin existe.

+0

Très bien, merci. Je me demandais à quoi sert le _SkipSourceChange? – Peter

Questions connexes