databind właściwości Source WebBrowser w WPF

85

Czy ktoś wie, jak databind właściwości .Source WebBrowser w WPF (3.5SP1)? Mam widok listy, w którym chcę mieć małą przeglądarkę internetową po lewej stronie i zawartość po prawej stronie oraz powiązać z danymi źródło każdego WebBrowser z identyfikatorem URI w każdym obiekcie powiązanym z elementem listy.

To jest to, co mam do tej pory jako dowód słuszności koncepcji, ale " <WebBrowser Source="{Binding Path=WebAddress}"" się nie kompiluje.

<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>
Russ
źródło

Odpowiedzi:

157

Problem polega na tym, że WebBrowser.Sourcenie jest to plik DependencyProperty. Jednym obejściem byłoby użycie AttachedPropertymagii, aby włączyć tę zdolność.

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

}

Następnie w swoim XAML wykonaj:

<WebBrowser ns:WebBrowserUtility.BindableSource="{Binding WebAddress}"/>
Todd White
źródło
9
Pobieranie wyjątku dla tego „nowego Uri (uri)”, ponieważ ciąg to „”. Być może powinno to być .... browser.Source = string.IsNullOrEmpty (uri)? null: nowy Uri (uri);
midspace
5
Należy zauważyć, że jest to powiązanie tylko w jedną stronę, a właściwość BindableSource nie zmieni się po zmianie strony przeglądarki internetowej.
Kurren
1
Jako nowicjuszowi było to trochę trudne do naśladowania - napisanie czegoś o posiadaniu prywatno-publicznego ustawiacza pobierającego dla „WebAddress” w powiązanym modelu ViewModel ze zdarzeniem aktualizacji dla zmiany właściwości pomogłoby. ten projekt ma podobny przykład. github.com/thoemmi/WebBrowserHelper
pgee70
dzięki. Wziąłem to i zmodyfikowałem, aby zaimplementować właściwość „Html”, która wywołuje NavigateToString pod maską.
Antony Scott
@ pgee70 dzięki, podążyłem za twoim przykładem z github i działa jak gratka
percentum
33

Poprawiłem trochę doskonałą odpowiedź Todda, aby stworzyć wersję, która radzi sobie ze stringami lub Uris ze źródła Binding:

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;
    }
Samuel Jack
źródło
31

Napisałem wrapper usercontrol, który wykorzystuje DependencyProperties:

XAML:

<UserControl x:Class="HtmlBox">
    <WebBrowser x:Name="browser" />
</UserControl>

DO#:

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

i używaj go tak:

<Controls:HtmlBox HtmlText="{Binding MyHtml}"  />

Jedynym problemem związanym z tym jest to, że formant WebBrowser nie jest „czystym” wpf… w rzeczywistości jest tylko opakowaniem komponentu win32. Oznacza to, że formant nie będzie uwzględniał indeksu z i zawsze będzie nakładał się na inny element (np. W przeglądarce scrollviewer może to powodować problemy) więcej informacji o problemach z win32-wpf w witrynie MSDN

RoelF
źródło
Właśnie tego potrzebowałem, ponieważ chcę wyświetlić własny kod HTML. Zgrabny, prosty i prawie rozumiem, co robi (-:
Murph
3

Fajny pomysł Todd.

Zrobiłem teraz podobnie z RichTextBox.Selection.Text w Silverlight 4. Dzięki za twój post. Działa w porządku.

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

Oto kod Xaml.

<RichTextBox IsReadOnly='False' TextWrapping='Wrap' utilities:RichTextBoxHelper.BindableSelectionText="{Binding Content}"/>
Olaf Japp
źródło
0

Jest to udoskonalenie odpowiedzi Todda i Samuela, aby skorzystać z pewnych podstawowych założeń logicznych, a także użyć operatora koalescencji zerowej.

public static void BindableSourcePropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
    WebBrowser browser = o as WebBrowser;

    if ((browser != null) && (e.NewValue != null))
        browser.Source = e.NewValue as Uri ?? new Uri((string)e.NewValue);

}
  1. Jeśli przeglądarka jest pusta lub lokalizacja jest pusta, nie możemy używać pustej strony ani nawigować do niej.
  2. Jeśli elementy w # 1 nie są zerowe, to podczas przypisywania, jeśli nową wartością jest identyfikator URI, użyj go. Jeśli nie, a identyfikator URI ma wartość null, należy połączyć, ponieważ musi to być ciąg, który można umieścić w identyfikatorze URI; ponieważ # 1 wymusza, że ​​ciąg nie może być pusty.
ΩmegaMan
źródło
-3

Musisz zadeklarować to w pierwszych kilku liniach xamlpliku, który wskazuje na plik klasy

xmlns:reportViewer="clr-namespace:CoMS.Modules.Report" 
William
źródło