2009-09-05 13 views
11

Gracias a this question (click me!), tengo la propiedad Source de mi WebBrowser vinculando correctamente a mi ViewModel.¿Existe una forma MVVM amigable de utilizar el control WebBrowser en WPF?

Ahora me gustaría conseguir dos objetivos más:

  1. IsEnabled obtener la propiedad de mis botones Atrás y Adelante para unirse correctamente a las CanGoBack y CanGoForward propiedades del WebBrowser.
  2. Descubre cómo llamar a los métodos GoForward() y GoBack() sin recurrir al código subyacente y sin que ViewModel tenga que saber sobre el WebBrowser.

Tengo el siguiente (no de trabajo) de marcado XAML en la actualidad

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

Estoy seguro de que el problema es que CanGoBack y CanGoForward no son propiedades de dependencia (y no aplican INotifyChanged), pero no estoy muy seguro de cómo solucionarlo.

Preguntas:

  1. ¿Hay alguna manera de conectar las propiedades asociadas (como lo hice con Source) o algo similar para obtener los CanGoBack y CanGoForward fijaciones para trabajar?

  2. ¿Cómo se escribe GoBackCommand y GoForwardCommand, por lo que son independientes del código subyacente y ViewModel y se pueden declarar en el marcado?

Respuesta

4

He utilizado este en mi enlazable envoltorio navegador web:

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

Tenga en cuenta que he creado mi navegador web enlazable como FrameworkElement que expone DependencyProperties y llama a métodos en el elemento de navegador real, para poder establecer CommandBindings en eso.

De esta manera, puede usar los comandos de navegación predeterminados en su vista. Los controladores utilizados son:

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, gracias. Estoy un poco confuso acerca de cómo configuras tu clase 'FrameworkElement'. Supongo que tienes un campo 'webBrowser', pero ¿cómo logras que se muestre? Estaba pensando que necesitaría construir un 'UserControl' y poner el' WebBrowser' en, por ejemplo, 'Grid' en el control. ¿Cómo manejas esto con una clase que hereda 'FrameworkElement'? Gracias. – devuxer

+0

En realidad, no necesita un UserControl, un FrameworkElement está bien siempre y cuando lo configure correctamente. Mi implementación puede no ser la mejor, pero si quieres echarle un vistazo, el control se puede encontrar aquí: http://pastebin.com/m492dbd3f (si te preguntas acerca de BrowserViewModel, es el ViewModel del que las propiedades del control están destinadas , estoy seguro de que ya tienes tu propio ViewModel) – Botz3000

+0

// btw Si derivas de FrameworkElement, puedes llamar a AddVisualChild y AddLogicalChild para poner realmente el WebBrowser o cualquier otra cosa dentro de él – Botz3000

0

Su pregunta parece dar a entender que a fin de aplicar correctamente un patrón MVVM no se le permite tener ningún código subyacente. Pero tal vez agregar algo de código subyacente a su vista hará que sea mucho más fácil conectarlo con su modelo de visualización. Puede agregar propiedades de dependencia a la vista y escuchar los eventos INotifyPropertyChanged.

4

Para cualquiera que se encuentre con esta pregunta y quiera una solución completa, aquí está. Combina todas las sugerencias hechas en este hilo y los hilos enlazados (y otros a los que se vincula).

XAML: http://pastebin.com/aED9pvW8

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

Ejemplo XAML uso: http://pastebin.com/JpuNrFq8

Nota: El ejemplo se supone que su vista se une a un modelo de vista que proporciona la URL de origen para el navegador . Se proporciona una barra de navegación muy rudimentaria con botones de retroceso, avance y actualización, y barra de direcciones para demostración.

Disfrútalo. He establecido la caducidad en esos pastebin's a nunca, por lo que deberían estar disponibles mientras pastebin exista.

+0

Muy bien, gracias. Me preguntaba para qué está el _SkipSourceChange. – Peter

Cuestiones relacionadas