databind la proprietà Source del WebBrowser in WPF


85

Qualcuno sa come associare dati alla proprietà .Source del WebBrowser in WPF (3.5SP1)? Ho un listview che desidero avere un piccolo WebBrowser a sinistra e il contenuto a destra e associare l'origine di ogni WebBrowser con l'URI in ogni oggetto associato all'elemento dell'elenco.

Questo è ciò che ho come prova del concetto finora, ma " <WebBrowser Source="{Binding Path=WebAddress}"" non viene compilato.

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

Risposte:


157

Il problema è che WebBrowser.Sourcenon è un file DependencyProperty. Una soluzione alternativa sarebbe usare un po 'di AttachedPropertymagia per abilitare questa capacità.

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

}

Quindi nel tuo xaml fai:

<WebBrowser ns:WebBrowserUtility.BindableSource="{Binding WebAddress}"/>

9
Ottenere un'eccezione su quel "nuovo Uri (uri)" poiché la stringa è "". Forse dovrebbe essere .... browser.Source = string.IsNullOrEmpty (uri)? null: nuovo Uri (uri);
midspace

5
Si noti che questa è solo un'associazione unidirezionale e la proprietà BindableSource non cambierà quando la pagina del browser Web cambia.
Kurren

1
come principiante questo è stato un po 'difficile da seguire per me: scrivere qualcosa sull'avere un getter setter pubblico-privato per "WebAddress" nel ViewModel associato con un evento di aggiornamento per la proprietà modificata avrebbe aiutato. questo progetto ha un esempio simile. github.com/thoemmi/WebBrowserHelper
pgee70

Grazie. Ho preso questo e l'ho modificato per implementare una proprietà "Html", che chiama NavigateToString sotto il cofano.
Antony Scott

@ pgee70 grazie, ho seguito il tuo esempio su GitHub e funziona a meraviglia
percentum

33

Ho modificato un po 'l'eccellente risposta di Todd per produrre una versione che gestisca le stringhe o Uris dalla fonte 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;
    }

31

Ho scritto un wrapper usercontrol, che fa uso delle 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);
    }
}

e usalo in questo modo:

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

L'unico problema con questo è che il controllo WebBrowser non è "puro" wpf ... in realtà è solo un wrapper per un componente win32. Ciò significa che il controllo non rispetterà lo z-index e si sovrapporrà sempre ad altri elementi (ad esempio: in uno scrollviewer questo potrebbe causare qualche problema) maggiori informazioni su questi problemi di win32-wpf su MSDN


Questo è esattamente ciò di cui avevo bisogno perché voglio visualizzare il mio HTML. Pulito, semplice e ho quasi capito cosa sta facendo (-:
Murph

3

Bella idea Todd.

Ho fatto lo stesso con RichTextBox.Selection.Text in Silverlight 4 ora. Grazie per il tuo post Funziona bene.

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

Ecco il codice Xaml.

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


0

Questo è un perfezionamento della risposta di Todd e Samuel per trarre vantaggio da alcune premesse logiche di base e utilizzare l'operatore di coalescenza nullo.

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. Se il browser è nullo o la posizione è nullo, non possiamo utilizzare o navigare a una pagina nulla.
  2. Quando gli elementi in # 1 non sono nulli, durante l'assegnazione, se il nuovo valore è un URI, usalo. In caso contrario e l'URI è nullo, allora deve essere una stringa che può essere inserita in un URI; poiché # 1 impone che la stringa non possa essere nulla.

-3

È necessario dichiararlo nelle prime righe del xamlfile che punta al file di classe

xmlns:reportViewer="clr-namespace:CoMS.Modules.Report" 
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.