databind свойство Source WebBrowser в WPF

85

Кто-нибудь знает, как привязать свойство .Source WebBrowser в WPF (3.5SP1)? У меня есть представление списка, в котором я хочу иметь небольшой 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. Один из обходных путей - использовать некоторую 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);
мидспейс
5
Обратите внимание, что это только односторонняя привязка, и свойство BindableSource не изменится при изменении страницы веб-браузера.
Kurren
1
как новичку мне было немного сложно уследить за этим - помогло бы написать что-нибудь о том, чтобы установить частный-общедоступный геттер для "WebAddress" в связанной ViewModel с событием обновления для свойства изменено. в этом проекте есть похожий пример. github.com/thoemmi/WebBrowserHelper
pgee70
Спасибо. Я взял это и изменил, чтобы реализовать свойство «Html», которое вызывает под капотом NavigateToString.
Энтони Скотт
@ pgee70, спасибо, я последовал твоему примеру на github и
отлично
33

Я немного изменил отличный ответ Тодда, чтобы создать версию, которая справляется со строками или Uris из источника привязки:

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

Я написал обертку usercontrol, которая использует 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);
    }
}

и используйте его так:

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

Единственная проблема с этим состоит в том, что элемент управления WebBrowser не является "чистым" wpf ... на самом деле это просто оболочка для компонента win32. Это означает, что элемент управления не будет учитывать z-index и всегда будет перекрывать другой элемент (например: в программе просмотра прокрутки это может вызвать некоторые проблемы). Подробнее об этих проблемах с win32-wpf в MSDN

RoelF
источник
Это именно то, что мне нужно, так как я хочу отображать свой собственный html. Аккуратно, просто, и я почти понимаю, что он делает (-:
Murph
3

Классная идея Тодда.

Я сделал то же самое с RichTextBox.Selection.Text в Silverlight 4. Спасибо за ваш пост. Работает отлично.

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

<RichTextBox IsReadOnly='False' TextWrapping='Wrap' utilities:RichTextBoxHelper.BindableSelectionText="{Binding Content}"/>
Олаф Джепп
источник
0

Это уточнение ответа Тодда и Самуэля, позволяющее воспользоваться некоторыми базовыми логическими предпосылками, а также использовать оператор объединения с нулевым значением.

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, мы не можем использовать или перейти на пустую страницу.
  2. Если элементы в № 1 не равны нулю, тогда при назначении, если новое значение является URI, используйте его. Если нет и URI равен нулю, то объединение должно быть строкой, которая может быть помещена в URI; поскольку # 1 требует, чтобы строка не могла быть нулевой.
ΩmegaMan
источник
-3

Вам нужно объявить его в первых нескольких строках xamlфайла, который указывает на файл класса.

xmlns:reportViewer="clr-namespace:CoMS.Modules.Report" 
Уильям
источник