かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

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属性が効くようになります。

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