c# - databind la propiedad Source del WebBrowser en WPF
xaml data-binding (7)
¿Alguien sabe cómo enlazar datos con la propiedad .Source del WebBrowser en WPF (3.5SP1)? Tengo una vista de lista que quiero tener un pequeño WebBrowser a la izquierda, y el contenido a la derecha, y para enlazar el origen de cada WebBrowser con el URI en cada objeto vinculado al elemento de la lista.
Esto es lo que tengo como una prueba de concepto hasta ahora, pero el " <WebBrowser Source="{Binding Path=WebAddress}"
" no se compila.
<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>
Buena idea Todd.
He hecho algo similar con RichTextBox.Selection.Text en Silverlight 4 ahora. Gracias por tu publicación. Funciona 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;
}
}
}
Aquí está el código Xaml.
<RichTextBox IsReadOnly=''False'' TextWrapping=''Wrap'' utilities:RichTextBoxHelper.BindableSelectionText="{Binding Content}"/>
Debes declararlo en las primeras líneas del archivo xaml
que apunta al archivo de la clase
xmlns:reportViewer="clr-namespace:CoMS.Modules.Report"
El problema es que WebBrowser.Source no es DependencyProperty. Una solución alternativa sería usar algo de magia AttachedProperty para habilitar esta habilidad.
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;
}
}
}
Entonces, en tu xaml haz:
<WebBrowser ns:WebBrowserUtility.BindableSource="{Binding WebAddress}"/>
Escribí un contenedor usercontrol, que hace uso de DependencyProperties:
XAML:
<UserControl x:Class="HtmlBox">
<WebBrowser x:Name="browser" />
</UserControl>
DO#:
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);
}
}
y úsalo así:
<Controls:HtmlBox HtmlText="{Binding MyHtml}" />
El único problema con esto es que el control WebBrowser no es wpf "puro" ... en realidad es solo un contenedor para un componente win32. Esto significa que el control no respetará el índice Z, y siempre se superpondrá a otro elemento (por ejemplo: en un visualizador de desplazamiento esto podría causar algunos problemas) más información sobre estos problemas de win32-wpf en MSDN
Este es un refinamiento de la respuesta de Todd y Samuel para aprovechar algunas premisas lógicas básicas, así como también usar el operador nulo coalescente.
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);
}
- Si el navegador es nulo o la ubicación es nula, no podemos usar o navegar a una página nula.
- Cuando los elementos del n. ° 1 no son nulos, al asignar, si el nuevo valor es un URI, utilícelo. Si no es así y el URI es nulo, entonces se unirá porque tiene que ser una cadena que se puede poner en un URI; ya que el n. ° 1 impone que la cadena no puede ser nula.
He modificado un poco la excelente respuesta de Todd para producir una versión que haga frente a cualquiera de las cadenas o Uris de la fuente de enlace:
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;
}
También puede usar un control de proxy especial por separado . Es aplicable no solo al caso WebBrowser, sino a cualquier control de este tipo.