WPFのWebBrowserのSourceプロパティをdatabindします


85

WPF(3.5SP1)でWebBrowserの.Sourceプロパティをデータバインドする方法を知っている人はいますか?左側に小さなWebBrowser、右側にコンテンツを配置し、各WebBrowserのソースをリストアイテムにバインドされた各オブジェクトのURIにデータバインドするリストビューがあります。

これは私がこれまでの概念実証として持っているものですが、「<WebBrowser Source="{Binding Path=WebAddress}"」はコンパイルされません。

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

回答:


157

問題は、でWebBrowser.SourceはないということDependencyPropertyです。1つの回避策はAttachedProperty、この機能を有効にするためにいくつかの魔法を使用することです。

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

}

次に、xamlで次のことを行います。

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

9
文字列が「」であるため、その「新しいURI(uri)」で例外を取得します。おそらくそれは.... browser.Source = string.IsNullOrEmpty(uri)?null:新しいURI(uri);
ミッドスペース2011年

5
これは一方向のバインディングにすぎず、Webブラウザページが変更されてもBindableSourceプロパティは変更されないことに注意してください。
クレン2015年

1
初心者として、これを理解するのは少し難しかったです。プロパティの更新イベントを変更して、バインドされたViewModelに「WebAddress」のプライベートパブリックゲッターセッターを作成することについて何かを書くと役に立ちました。このプロジェクトにも同様の例があります。github.com/thoemmi/WebBrowserHelper
pgee70

ありがとう。私はこれを取り、内部でNavigateToStringを呼び出す「Html」プロパティを実装するように変更しました。
アントニースコット

@ pgee70ありがとう、私はあなたのgithubの例に従い、おやつをします
パーセント

33

Toddの優れた回答を少し修正して、Bindingソースの文字列またはURIのいずれかに対応するバージョンを作成しました。

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

DependencyPropertiesを利用するラッパーusercontrolを作成しました。

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

そしてそれをそのように使用します:

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

これに関する唯一の問題は、WebBrowserコントロールが「純粋な」wpfではないことです...実際には、win32コンポーネントの単なるラッパーです。これは、コントロールがz-indexを尊重せず、常に他の要素をオーバーレイすることを意味します(たとえば、スクロールビューアでは、これにより問題が発生する可能性があります)。MSDNでのこれらのwin32-wpfの問題に関する詳細情報


自分のHTMLを表示したいので、これがまさに必要なものです。きちんとしていて、シンプルで、私はそれが何をしているのかほとんど理解しています(-:
Murph 2011年

3

クールなアイデアトッド。

Silverlight4のRichTextBox.Selection.Textでも同様のことを行いました。投稿ありがとうございます。正常に動作します。

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

これがXamlコードです。

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


0

これは、いくつかの基本的な論理前提を利用し、null合体演算子を使用するためのToddとSamuelの回答を改良したものです。

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. ブラウザがnullまたは場所がnullの場合、nullページを使用またはナビゲートすることはできません。
  2. #1の項目がnullでない場合、割り当てるときに、新しい値がURIの場合は、それを使用します。そうではなく、URIがnullの場合、合体はURIに入れることができる文字列である必要があります。#1は、文字列をnullにすることはできないことを強制するためです。

-3

xamlクラスファイルを指しているファイルの最初の数行で宣言する必要があります

xmlns:reportViewer="clr-namespace:CoMS.Modules.Report" 
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.