Quantcast
Channel: かずきのBlog@hatena
Viewing all articles
Browse latest Browse all 1387

UWPで色付きTextBlockを作ろう

$
0
0

Textプロパティに所定の書式に従った文字列突っ込んだらいい感じに色つけて表示してくれるTextBlockみたいなのが欲しくなることってないでしょうか。

そんな時は、TextBlockを1枚ラップしたカスタムコントロールかユーザーコントロールを作ると捗ります。今回は、実装が簡単なユーザーコントロールを例に作ってみたいと思います。

ColoredTextBlockという名前でユーザーコントロールを作って以下のようにTextBlockを置きます。

<UserControl x:Class="ColoredTextBlock.ColoredTextBlock"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="using:ColoredTextBlock"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"mc:Ignorable="d"d:DesignHeight="300"d:DesignWidth="400"><Grid><TextBlock x:Name="TextBlock" /></Grid></UserControl>

そして、このユーザーコントロールにText依存関係プロパティを作ります。Textが変更されたときのコールバックでTextをパースしてTextBlockのInlinesを組み立てます。

using System.Reflection;
using System.Xml.Linq;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Documents;
using Windows.UI.Xaml.Media;

namespace ColoredTextBlock
{
    publicsealedpartialclass ColoredTextBlock : UserControl
    {
        publicstaticreadonly DependencyProperty TextProperty =
            DependencyProperty.Register(
                nameof(Text),
                typeof(string),
                typeof(ColoredTextBlock),
                new PropertyMetadata(null, (s, e) =>
                {
                    ((ColoredTextBlock)s).Parse();
                }));

        publicstring Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }

        privatevoid Parse()
        {
            // ここで文字列をパースしてInlinesを組み立てる
        }

        public ColoredTextBlock()
        {
            this.InitializeComponent();
        }
    }
}

今回はXML形式でFontタグにColor属性で色を指定できるみたいなのをイメージして以下のようなパース処理を実装しました。

this.TextBlock.Inlines.Clear();
try
{
    var doc = XDocument.Parse(this.Text);
    foreach (var node in doc.Root.Nodes())
    {
        if (node.NodeType == System.Xml.XmlNodeType.Text)
        {
            var textNode = (XText)node;
            this.TextBlock.Inlines.Add(new Run
            {
                Text = textNode.Value
            });
        }
        elseif (node.NodeType == System.Xml.XmlNodeType.Element)
        {
            var elm = (XElement)node;
            if (elm.Name != "Font")
            {
                continue;
            }

            var color = elm.Attribute("Color")?.Value ?? "Black";
            var text = elm.Value;

            var property = (Color)(typeof(Colors).GetTypeInfo().GetDeclaredProperty(color)?.GetValue(null) ?? Colors.Black);
            this.TextBlock.Inlines.Add(new Run
            {
                Text = text,
                Foreground = new SolidColorBrush(property)
            });
        }
    }
}
catch { }

以下のようにTextBoxの入力とバインドして使ってみます。

<Page x:Class="ColoredTextBlock.MainPage"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="using:ColoredTextBlock"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"mc:Ignorable="d"><StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"><TextBox x:Name="TextBox"Text="&lt;Doc&gt;&lt;Font Color='Blue'&gt;Hello&lt;/Font&gt;&lt;Font Color='Red'&gt;World&lt;/Font&gt;&lt;/Doc&gt;" /><local:ColoredTextBlock Text="{x:Bind TextBox.Text, Mode=OneWay}" /></StackPanel></Page>

実行すると以下のようになります。

f:id:okazuki:20160227221833p:plain

ソースコード

ソースコードの全体はGitHubに上げています。

github.com


Viewing all articles
Browse latest Browse all 1387

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>