views:

3144

answers:

5

Does anyone know how to databind the .Source property of the WebBrowser in WPF ( 3.5SP1 )? I have a listview that I want to have a small WebBrowser on the left, and content on the right, and to databind the source of each WebBrowser with the URI in each object bound to the list item.

This is what I have as a proof of concept so far, but the "<WebBrowser Source="{Binding Path=WebAddress}"" does not compile.

<DataTemplate x:Key="dealerLocatorLayout" DataType="DealerLocatorAddress">                
                    <StackPanel Orientation="Horizontal">
                         <!--Web Control Here-->
                        <WebBrowser Source="{Binding Path=WebAddress}"
                            ScrollViewer.HorizontalScrollBarVisibility="Disabled" 
                            ScrollViewer.VerticalScrollBarVisibility="Disabled" 
                            Width="300"
                            Height="200"
                            />
                        <StackPanel Orientation="Vertical">
                            <StackPanel Orientation="Horizontal">
                                <Label Content="{Binding Path=CompanyName}" FontWeight="Bold" Foreground="Blue" />
                                <TextBox Text="{Binding Path=DisplayName}" FontWeight="Bold" />
                            </StackPanel>
                            <TextBox Text="{Binding Path=Street[0]}" />
                            <TextBox Text="{Binding Path=Street[1]}" />
                            <TextBox Text="{Binding Path=PhoneNumber}"/>
                            <TextBox Text="{Binding Path=FaxNumber}"/>
                            <TextBox Text="{Binding Path=Email}"/>
                            <TextBox Text="{Binding Path=WebAddress}"/>
                        </StackPanel>
                </StackPanel>
            </DataTemplate>
+16  A: 

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 = uri != null ? new Uri(uri) : null;
     }
    }

}

Then in your xaml do:

<WebBrowser ns:WebBrowserUtility.BindableSource="{Binding WebAddress}"
    ScrollViewer.HorizontalScrollBarVisibility="Disabled" 
    ScrollViewer.VerticalScrollBarVisibility="Disabled" 
    Width="300"
    Height="200" />
Todd White
A: 

i can use ns:...

Error 1 ''ns' is an undeclared namespace. Line 11, position 78.' XML is not valid. View\JukeboxUserControl.xaml

+6  A: 

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

Roel
A: 

You may also use a special separate proxy control. It's applicable not only to the WebBrowser case, but to any such control.

Yacoder
+1  A: 

Cool idea Todd.

I have done similar with the RichTextBox.Selection.Text in Silverlight 4 now. Thanks for your post. Works fine.

public class RichTextBoxHelper
{
    public static readonly DependencyProperty BindableSelectionTextProperty =
       DependencyProperty.RegisterAttached("BindableSelectionText", typeof(string), 
       typeof(RichTextBoxHelper), new PropertyMetadata(null, BindableSelectionTextPropertyChanged));

    public static string GetBindableSelectionText(DependencyObject obj)
    {
        return (string)obj.GetValue(BindableSelectionTextProperty);
    }

    public static void SetBindableSelectionText(DependencyObject obj, string value)
    {
        obj.SetValue(BindableSelectionTextProperty, value);
    }

    public static void BindableSelectionTextPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
    {
        RichTextBox rtb = o as RichTextBox;
        if (rtb != null)
        {
            string text = e.NewValue as string;
            if (text != null)
                rtb.Selection.Text = text;
        }
    }
}    

Here is the Xaml-Code.

<RichTextBox IsReadOnly='False' TextWrapping='Wrap' utilities:RichTextBoxHelper.BindableSelectionText="{Binding Content}"/>
Lebenskünstler