Datenbinden Sie die Source-Eigenschaft des WebBrowser in WPF

85

Weiß jemand, wie man die .Source-Eigenschaft des WebBrowser in WPF (3.5SP1) datenbindet? Ich habe eine Listenansicht, in der ich links einen kleinen WebBrowser und rechts einen Inhalt haben und die Quelle jedes WebBrowser mit dem URI in jedem an das Listenelement gebundenen Objekt datenbinden möchte.

Dies ist, was ich bisher als Proof of Concept habe, aber das " <WebBrowser Source="{Binding Path=WebAddress}"" kompiliert nicht.

<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
quelle

Antworten:

157

Das Problem ist, dass WebBrowser.Sourcees kein ist DependencyProperty. Eine Problemumgehung wäre, etwas AttachedPropertyMagie zu verwenden, um diese Fähigkeit zu aktivieren.

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

}

Dann mache in deinem xaml:

<WebBrowser ns:WebBrowserUtility.BindableSource="{Binding WebAddress}"/>
Todd White
quelle
9
Eine Ausnahme für diesen "neuen Uri (uri)" erhalten, da der String "" ist. Vielleicht sollte es sein ... browser.Source = string.IsNullOrEmpty (uri)? null: neuer Uri (uri);
Midspace
5
Beachten Sie, dass dies nur eine Einwegbindung ist und sich die BindableSource-Eigenschaft nicht ändert, wenn sich die Webbrowserseite ändert.
Kurren
1
Als Neuling war es für mich etwas schwierig, dem zu folgen. Es hätte geholfen, etwas darüber zu schreiben, wie man einen privat-öffentlichen Getter-Setter für "WebAddress" im gebundenen ViewModel mit einem Update-Ereignis für "Property Property" hat. Dieses Projekt hat ein ähnliches Beispiel. github.com/thoemmi/WebBrowserHelper
pgee70
Vielen Dank. Ich nahm dies und änderte es, um eine "Html" -Eigenschaft zu implementieren, die NavigateToString unter der Haube aufruft.
Antony Scott
@ pgee70 danke, ich bin deinem Github-Beispiel gefolgt und arbeite an einem Leckerbissen
Perzentum
33

Ich habe die ausgezeichnete Antwort von Todd ein wenig geändert, um eine Version zu erstellen, die entweder mit Strings oder Uris aus der Binding-Quelle zurechtkommt:

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
quelle
31

Ich habe eine Wrapper-Benutzersteuerung geschrieben, die die DependencyProperties verwendet:

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

und benutze es so:

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

Das einzige Problem dabei ist, dass das WebBrowser-Steuerelement kein "reines" wpf ist ... es ist eigentlich nur ein Wrapper für eine Win32-Komponente. Dies bedeutet, dass das Steuerelement den Z-Index nicht berücksichtigt und immer ein anderes Element überlagert (z. B. in einem Scrollviewer kann dies zu Problemen führen). Weitere Informationen zu diesen win32-wpf-Problemen in MSDN

RoelF
quelle
Dies ist genau das, was ich brauchte, um mein eigenes HTML anzuzeigen. Ordentlich, einfach, und ich verstehe fast, was es tut (-:
Murph
3

Coole Idee Todd.

Ähnliches habe ich jetzt mit der RichTextBox.Selection.Text in Silverlight 4 gemacht. Danke für deinen Beitrag. Funktioniert gut.

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

Hier ist der Xaml-Code.

<RichTextBox IsReadOnly='False' TextWrapping='Wrap' utilities:RichTextBoxHelper.BindableSelectionText="{Binding Content}"/>
Olaf Japp
quelle
0

Dies ist eine Verfeinerung der Antwort von Todd und Samuel, um einige grundlegende logische Prämissen zu nutzen und den Null-Koaleszenz-Operator zu verwenden.

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. Wenn der Browser null oder der Speicherort null ist, können wir keine Nullseite verwenden oder zu dieser navigieren.
  2. Wenn die Elemente in # 1 nicht null sind, verwenden Sie sie beim Zuweisen, wenn der neue Wert ein URI ist. Wenn nicht und der URI null ist, muss es sich um eine Zeichenfolge handeln, die in einen URI eingefügt werden kann. da # 1 erzwingt, dass die Zeichenfolge nicht null sein kann.
ΩmegaMan
quelle
-3

Sie müssen es in den ersten Zeilen der xamlDatei deklarieren, die auf die Klassendatei verweist

xmlns:reportViewer="clr-namespace:CoMS.Modules.Report" 
Wilhelm
quelle