Есть ли MVVM-удобный способ использования элемента управления WebBrowser в WPF?
Благодаря этот вопрос (щелкните по мне!), у меня есть свойство Source
моего привязки WebBrowser
к моей ViewModel.
Теперь я хотел бы достичь еще двух целей:
- Получите свойство
IsEnabled
моих кнопок Back и Forward для правильной привязки к свойствам CanGoBack
и CanGoForward
WebBrowser
.
- Выясните, как вызвать методы
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="< Back" />
<Button
Style="{StaticResource Button_Style}"
Grid.Column="4"
IsEnabled="{Binding ElementName=_instructionsWebBrowser, Path=CanGoForward}"
Command="{Binding GoForwardCommand}"
Content="Forward >" />
Я уверен, проблема в том, что CanGoBack
и CanGoForward
не являются свойствами зависимостей (и не реализуют INotifyChanged
), но я не совсем уверен, как обойти это.
Вопросы:
-
Есть ли способ подключить прикрепленные свойства (как это было в случае с Source
) или что-то подобное, чтобы заставить привязки CanGoBack
и CanGoForward
работать?
-
Как написать GoBackCommand
и GoForwardCommand
, чтобы они были независимы от кода и ViewModel и могут быть объявлены в разметке?
Ответы
Ответ 1
Я использовал это в своей привязываемой оболочке 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.
Таким образом, вы можете использовать навигационные команды по умолчанию в своем представлении.
Используемые обработчики:
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);
}
Ответ 2
Для тех, кто сталкивается с этим вопросом и хочет полного решения, вот оно. Он сочетает в себе все предложения, сделанные в этом потоке и связанных потоках (и другие ссылки, на которые ссылаются).
XAML:
http://pastebin.com/aED9pvW8
Класс С#:
http://pastebin.com/n6cW9ZBB
Пример использования XAML:
http://pastebin.com/JpuNrFq8
Примечание. В примере предполагается, что ваше представление привязывается к ViewModel, который предоставляет URL-адрес источника для браузера. Для демонстрации предусмотрена очень рудиментарная панель навигации с кнопками "назад", "вперед" и "Обновить" и адресная строка.
Enjoy. Я поставил истечение на те пастебины, чтобы никогда, поэтому они должны быть доступны до тех пор, пока существует пастебин.
Ответ 3
В вашем вопросе подразумевается, что для правильного внедрения шаблона MVVM вам не разрешается иметь какой-либо код. Но, возможно, добавление некоторого кода для вашего взгляда упростит его подключение к вашей модели представлений. Вы можете добавить свойства зависимостей в представление и позволить ему прослушивать события INotifyPropertyChanged
.