databind the Source property of the WebBrowser in WPF
The problem is that WebBrowser.Source
is not a DependencyProperty
. One workaround would be to use some AttachedProperty
magic to enable this ability.
public static class WebBrowserUtility{ public static readonly DependencyProperty BindableSourceProperty = DependencyProperty.RegisterAttached("BindableSource", typeof(string), typeof(WebBrowserUtility), new UIPropertyMetadata(null, BindableSourcePropertyChanged)); public static string GetBindableSource(DependencyObject obj) { return (string) obj.GetValue(BindableSourceProperty); } public static void SetBindableSource(DependencyObject obj, string value) { obj.SetValue(BindableSourceProperty, value); } public static void BindableSourcePropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) { WebBrowser browser = o as WebBrowser; if (browser != null) { string uri = e.NewValue as string; browser.Source = !String.IsNullOrEmpty(uri) ? new Uri(uri) : null; } }}
Then in your xaml do:
<WebBrowser ns:WebBrowserUtility.BindableSource="{Binding WebAddress}"/>
I've amended Todd's excellent answer a little to produce a version that copes with either strings or Uris from the Binding source:
public static class WebBrowserBehaviors{ public static readonly DependencyProperty BindableSourceProperty = DependencyProperty.RegisterAttached("BindableSource", typeof(object), typeof(WebBrowserBehaviors), new UIPropertyMetadata(null, BindableSourcePropertyChanged)); public static object GetBindableSource(DependencyObject obj) { return (string)obj.GetValue(BindableSourceProperty); } public static void SetBindableSource(DependencyObject obj, object value) { obj.SetValue(BindableSourceProperty, value); } public static void BindableSourcePropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) { WebBrowser browser = o as WebBrowser; if (browser == null) return; Uri uri = null; if (e.NewValue is string ) { var uriString = e.NewValue as string; uri = string.IsNullOrWhiteSpace(uriString) ? null : new Uri(uriString); } else if (e.NewValue is Uri) { uri = e.NewValue as Uri; } browser.Source = uri; }
I wrote a wrapper usercontrol, which makes use of the DependencyProperties:
XAML:
<UserControl x:Class="HtmlBox"> <WebBrowser x:Name="browser" /></UserControl>
C#:
public static readonly DependencyProperty HtmlTextProperty = DependencyProperty.Register("HtmlText", typeof(string), typeof(HtmlBox));public string HtmlText { get { return (string)GetValue(HtmlTextProperty); } set { SetValue(HtmlTextProperty, value); }}protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) { base.OnPropertyChanged(e); if (e.Property == HtmlTextProperty) { DoBrowse(); }} private void DoBrowse() { if (!string.IsNullOrEmpty(HtmlText)) { browser.NavigateToString(HtmlText); }}
and use it like so:
<Controls:HtmlBox HtmlText="{Binding MyHtml}" />
The only trouble with this one is that the WebBrowser control is not "pure" wpf... it is actually just a wrapper for a win32 component. This means that the control won't respect the z-index, and will always overlay other element (eg: in a scrollviewer this might cause some trouble)more info about these win32-wpf issues on MSDN