redwarrior’s diary

C#, ASP.NET, WEB, G*などの雑多な情報

エラーメッセージがViewを切り替えると消える事への対処方法

課題

f:id:redwarrior:20200718152439p:plain
バリエーションエラー

一つ前の記事で、第5回のエラー処理のサンプルを作成した時に、バリエーションによるエラーメッセージを表示した状態で、一覧から別の項目を選択すると、Viewが切り替わり、右側に新しい画面が表示される。
その後、元の項目を表示すると再びViewが切り替わり、バリエーションエラーが発生している画面が表示される。

この時、切り替え前には表示されていたエラーメッセージが消えてしまう。入力フォームに赤い枠があるため、バリエーションエラーは発生しているのがわかる。

AdornedElement の関連の設定だと思い、色々と調べた結果、Viewが切り替わってもエラーメッセージが消えない方法を編み出した。

エラー処理で検索してヒットするのは、WPF コントロール(TextBox)等のValidation.ErrorTemplate プロパティに、リソースとして定義しておいたControlTemplateを設定する方法だが、
この方法だと上記の通りViewが切り替わるとエラーメッセージが消えてしまう。

参考: Nine Works INotifyDataErrorInfoを使用したデータ検証

そこで、Validation.ErrorTemplate への設定方法を変えると上手くいく。

対処方法

<UserControl.Resources>
    <Style x:Key="ErrorStyle" TargetType="TextBox">
        <Setter Property="Margin" Value="4" />
        <Style.Triggers>
            <Trigger Property="IsVisible" Value="True">
                <Setter Property="Validation.ErrorTemplate">
                    <Setter.Value>
                        <ControlTemplate>
                            <DockPanel>
                                <ItemsControl DockPanel.Dock="Bottom" Margin="5,0"
                                              ItemsSource="{Binding ElementName=adornedElement, Path=AdornedElement.(Validation.Errors)}">
                                    <ItemsControl.ItemTemplate>
                                        <DataTemplate>
                                            <TextBlock Text="{Binding ErrorContent}" Foreground="Red"/>
                                        </DataTemplate>
                                    </ItemsControl.ItemTemplate>
                                </ItemsControl>
                                <Border BorderBrush="Red" BorderThickness="1"
                                        Width="{Binding ElementName=adornedElement, Path=ActualWidth}"
                                        Height="{Binding ElementName=adornedElement, Path=ActualHeight}">
                                    <AdornedElementPlaceholder Name="adornedElement"/>
                                </Border>
                            </DockPanel>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Trigger>
        </Style.Triggers>
    </Style>
</UserControl.Resources>

コントロールの属性として指定するのではなく、Styleに設定し、条件を満たしたときに反映されるようにする。

具体的には、Style.Triggerを使用して指定する。トリガーの条件は「IsVisible」プロパティが 「true」になっている事。
条件を満たした場合、Validation.ErrorTemplate にControlTemplateを設定するようにすると、Viewを切り替えてもエラーメッセージが表示される。

使用する場合は、Styleプロパティに設定する。

<TextBox Text="{Binding Author, UpdateSourceTrigger=PropertyChanged}" Width="200" Margin="5,0,5,20" HorizontalAlignment="Left"
         Style="{StaticResource ErrorStyle}"></TextBox>

ちなみに、エラーが発生しているかどうかはコントロールが持っており、エラーがなくなるとValidation.ErrorTemplate が空になってメッセージは消える。