かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

ReactivePropertyをValidationSummaryに対応させてみた

今作ってるKinkumaFramework 2.0は、ReactivePropertyとPrismで開発する際のライブラリを目指してるのですがMVVMのサポートはうすっぺらぺらになりそうです・・・。まぁそれは置いといてLabelとDescriptionViewerは対応できました。出来ましたというよりは、Silverlightの機能を使えばOKだったのでKinkumaFramework側で準備するものは何もありませんでした。


ということで、次は個人的に鬼門だと思ってたValidationSummaryです。こいつは何も考えないで使うと以下のようになります。まずはXAML。前回のDescriptionViewerとLabel対応のアプリに追記しました。

<UserControl 
    x:Class="RxPropLabelSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:l="clr-namespace:RxPropLabelSample"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400" 
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:kinkuma="clr-namespace:Codeplex.KinkumaFramework.Behaviors;assembly=KinkumaFramework.SL4">
    <UserControl.DataContext>
        <l:MainPageViewModel />
    </UserControl.DataContext>
    <StackPanel x:Name="LayoutRoot" Background="White">
        <!-- TextBoxをTargetにバインド -->
        <sdk:Label Target="{Binding ElementName=textBoxName}" PropertyPath="Name" />
        <!-- バリデーションエラーを表示するための余白のマージンを設定しています -->
        <TextBox Name="textBoxName" Margin="5,5,250,5" Text="{Binding Path=Name.Value, Mode=TwoWay, ValidatesOnDataErrors=True, NotifyOnValidationError=True}" />
        <!-- TextBoxをTargetにバインド -->
        <sdk:DescriptionViewer Target="{Binding ElementName=textBoxName}" PropertyPath="Name" />
        <Button Content="Dummy" />
        <sdk:ValidationSummary />
    </StackPanel>
</UserControl>

これを実行して、検証エラーを出すとなんとも悲しい結果になります。ValidationSummaryに表示されるプロパティ名がValueになってしまうんですよね。

これはValidationSummaryが内部で、かなり泥臭くBindingのPathやらを解析しててハードコーディングされてる結果なので割り込む余地がありません。ということで、色々悩んだあげくこっちも泥臭くいくことにしました。ValidationSummaryのErrorsにValidationSummaryItemが追加されたタイミングでReactivePropertyに対するエラーっぽかったら泥臭い解析をしてReactiveProperty型のプロパティにつけられているDisplayプロパティを探してきています。ソースはここに載せるにはちょっと長いので興味のある人はリポジトリから参照してください。


使う側はすっきりと使えるようにしています。BehaviorをValidationSummaryに追加するだけでOKです。XAMLは以下のようになります。

<UserControl 
    x:Class="RxPropLabelSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:l="clr-namespace:RxPropLabelSample"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400" 
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:kinkuma="clr-namespace:Codeplex.KinkumaFramework.Behaviors;assembly=KinkumaFramework.SL4">
    <UserControl.DataContext>
        <l:MainPageViewModel />
    </UserControl.DataContext>
    <StackPanel x:Name="LayoutRoot" Background="White">
        <!-- TextBoxをTargetにバインド -->
        <sdk:Label Target="{Binding ElementName=textBoxName}" PropertyPath="Name" />
        <!-- バリデーションエラーを表示するための余白のマージンを設定しています -->
        <TextBox Name="textBoxName" Margin="5,5,250,5" Text="{Binding Path=Name.Value, Mode=TwoWay, ValidatesOnDataErrors=True, NotifyOnValidationError=True}" />
        <!-- TextBoxをTargetにバインド -->
        <sdk:DescriptionViewer Target="{Binding ElementName=textBoxName}" PropertyPath="Name" />
        <Button Content="Dummy" />
        <sdk:ValidationSummary>
            <!-- ReactivePropertyのサポートを追加するBehaviorを設定 -->
            <i:Interaction.Behaviors>
                <kinkuma:ValidationSummaryReactivePropertySupportBehavior />
            </i:Interaction.Behaviors>
        </sdk:ValidationSummary>
    </StackPanel>
</UserControl>

これで実行するとReactiveProperty型のプロパティに指定したDisplay属性が効くようになります。

結構泥臭い上に、まだちゃんとテストも出来てないのでバグがあるかも・・・。