web-dev-qa-db-fra.com

lier la propriété Source du WebBrowser dans WPF

Quelqu'un sait-il comment lier des données à la propriété .Source du WebBrowser dans WPF (3.5SP1)? J'ai une vue de liste que je veux avoir un petit WebBrowser à gauche, et du contenu à droite, et pour lier la source de chaque WebBrowser avec l'URI dans chaque objet lié à l'élément de liste.

C'est ce que j'ai jusqu'à présent comme preuve de concept, mais le "<WebBrowser Source="{Binding Path=WebAddress}" "ne compile pas.

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

Le problème est que WebBrowser.Source n'est pas un DependencyProperty. Une solution de contournement consisterait à utiliser de la magie AttachedProperty pour activer cette 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;
        }
    }

}

Ensuite, dans votre xaml, faites:

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

J'ai un peu modifié l'excellente réponse de Todd pour produire une version qui soit compatible avec les chaînes ou les uris de la source 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;
    }
32
Samuel Jack

J'ai écrit un wrapper usercontrol, qui utilise les 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);
    }
}

et l'utiliser comme ça:

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

Le seul problème avec celui-ci est que le contrôle WebBrowser n'est pas wpf "pur" ... c'est en fait juste un wrapper pour un composant win32. Cela signifie que le contrôle ne respectera pas le z-index, et superposera toujours les autres éléments (par exemple: dans un scrollviewer cela pourrait causer des problèmes) plus d'informations sur ces problèmes win32-wpf sur MSDN

30
RoelF

Cool idée Todd.

J'ai fait la même chose avec RichTextBox.Selection.Text dans Silverlight 4 maintenant. Merci pour votre message. Fonctionne bien.

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

Voici le Xaml-Code.

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

Vous pouvez également utiliser un contrôle proxy séparé spécial . Elle s'applique non seulement au cas WebBrowser, mais à tout contrôle de ce type.

1
Max Galkin

Ceci est un raffinement de la réponse de Todd et Samuel pour tirer parti de certaines prémisses de logique de base et utiliser l'opérateur de coalescence nulle.

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. Si le navigateur est nul ou l'emplacement est nul, nous ne pouvons pas utiliser ou naviguer vers une page nulle.
  2. Lorsque les éléments de # 1 ne sont pas nuls, lors de l'attribution, si la nouvelle valeur est un URI, utilisez-le. Si ce n'est pas le cas et que l'URI est nul, alors fusionnez car il doit s'agir d'une chaîne qui peut être insérée dans un URI; puisque # 1 impose que la chaîne ne puisse pas être nulle.
0
ΩmegaMan