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>
問題は、 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}"/>
Toddの優れた答えを少し修正して、Bindingソースの文字列または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;
}
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を尊重せず、常に他の要素をオーバーレイすることを意味します(たとえば、スクロールビューアーでは、これは何らかのトラブルを引き起こす可能性があります) [〜#〜] msdn [〜#〜]
クールなアイデアトッド。
Silverlight 4の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-Codeです。
<RichTextBox IsReadOnly='False' TextWrapping='Wrap' utilities:RichTextBoxHelper.BindableSelectionText="{Binding Content}"/>
特別な 個別のプロキシ制御 を使用することもできます。 WebBrowserの場合だけでなく、そのようなコントロールにも適用できます。
これは、いくつかの基本的な論理的前提を活用し、null合体演算子を使用するというトッドとサミュエルの答えの改良版です。
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);
}