2011年9月8日木曜日

Set HTML to WebBrowser in XAML (Windows Phone)

WebBrowser control in Microsoft.Phone.Controls has NavigateToString(string html) method which enables programmers to set HTML to a WebBrowser instance. However, because it is a method and not a property, it cannot be used in XAML files.

The following shows a way to add a property to WebBrowser via which you can set HTML to WebBrowser instances in XAML files. In this example, the property is named "Html". To understand the code below fully, you need to know about "attached properties", but you don't have to if you just want to use it (in such a case, just do copy & paste).

1. Write a class to provide the Html property

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;

namespace MyApp
{
    // Declare this class as a sub class of DependencyObject
    // because we need to register attached properties.
    public class WebBrowserAttachedProperties : DependencyObject
    {
        #region Html property

        public const string HtmlPropertyName = "Html";

        // Register an attached property.
        public static readonly DependencyProperty HtmlProperty
            = DependencyProperty.RegisterAttached(
                HtmlPropertyName,
                typeof(string),
                typeof(WebBrowserAttachedProperties),
                new PropertyMetadata(null, OnHtmlPropertyChanged));

        // Getter. The name of this method should not be changed
        // because the dependency system uses it.
        public static string GetHtml(DependencyObject obj)
        {
            return (string)obj.GetValue(HtmlProperty);
        }

        // Setter. The name of this method should not be changed
        // because the dependency system uses it.
        public static void SetHtml(DependencyObject obj, string value)
        {
            obj.SetValue(HtmlProperty, value);
        }

        // Called when the property value was changed.
        private static void OnHtmlPropertyChanged(
            DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            // The given object must be a WebBrowser instance.
            var browser = obj as WebBrowser;

            if (browser == null)
            {
                // The given object is not an instance of WebBrowser.
                return;
            }

            // The HTML to set to the WebBrowser instance.
            var html = args.NewValue as string;
            if (html == null)
            {
                html = string.Empty;
            }

            // Set the HTML to the WebBrowser instance.
            browser.NavigateToString(html);
        }

        #endregion
    }
}


2. Use the Html property in XAML

<phone:PhoneApplicationPage
    ......
    xmlns:local="clr-namespace:MyApp"
    >

    ......

    <!-- A TextBox instance to input HTML -->
    <TextBox x:Name="InputTextBox" />

    <!-- A WebBrowser instance which renders the content of InputTextBox -->
    <phone:WebBrowser
        local:WebBrowserAttachedProperties.Html="{Binding ElementName=InputTextBox, Path=Text}" />


XAML 内で WebBrowser に HTML をセットする (Windows Phone)


Microsoft.Phone.Controls にある WebBrowser コントロールには、NavigateToString(string html) というメソッドがあり、プログラマーはこれを用いて WebBrowser インスタンスに HTML をセットすることができる。しかし、これはプロパティーではなくメソッドなので、XAML ファイル内で使用することができない。

XAML ファイル内で WebBrowser インスタンスに HTML をセットすることを可能にするプロパティーを WebBrowser に追加する方法を下記に示す。この例では、当該プロパティーに Html という名前を付けている。下記のコードを完全に理解するには、アタッチトプロパティー について知っておく必要があるが、この仕組みを使いたいだけであれば、その必要はない(その場合はコピー&ペーストするだけで十分である)。

1. Html プロパティーを提供するクラスを書く

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;

namespace MyApp
{
    // アタッチトプロパティーを登録する必要があるので、
    // このクラスを DependencyObject のサブクラスとする。
    public class WebBrowserAttachedProperties : DependencyObject
    {
        #region Html property

        public const string HtmlPropertyName = "Html";

        // アタッチトプロパティーを登録する。
        public static readonly DependencyProperty HtmlProperty
            = DependencyProperty.RegisterAttached(
                HtmlPropertyName,
                typeof(string),
                typeof(WebBrowserAttachedProperties),
                new PropertyMetadata(null, OnHtmlPropertyChanged));

        // Getter メソッド。依存関係システムが使用するので、
        // このメソッドのメソッド名はこの通りで。
        public static string GetHtml(DependencyObject obj)
        {
            return (string)obj.GetValue(HtmlProperty);
        }

        // Setter メソッド。依存関係システムが使用するので、
        // このメソッドのメソッド名はこの通りで。
        public static void SetHtml(DependencyObject obj, string value)
        {
            obj.SetValue(HtmlProperty, value);
        }

        // プロパティーの値が変更されたときに呼ばれる。
        private static void OnHtmlPropertyChanged(
            DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            // 渡されたオブジェクトは WebBrowser のインスタンスでなければならない。
            var browser = obj as WebBrowser;

            if (browser == null)
            {
                // 渡されたオブジェクトは WebBrowser のインスタンスではなかった。
                return;
            }

            // WebBrowser インスタンスにセットする HTML
            var html = args.NewValue as string;
            if (html == null)
            {
                html = string.Empty;
            }

            // HTML を WebBrowser インスタンスにセットする。
            browser.NavigateToString(html);
        }

        #endregion
    }
}

2. Html プロパティーを XAML で使用する

<phone:PhoneApplicationPage
    ......
    xmlns:local="clr-namespace:MyApp"
    >

    ......

    <!-- HTML を入力するための TextBox -->
    <TextBox x:Name="InputTextBox" />

    <!-- InputTextBox の内容を描画するための WebBrowser インスタンス -->
    <phone:WebBrowser
        local:WebBrowserAttachedProperties.Html="{Binding ElementName=InputTextBox, Path=Text}" />