none
IDataErrorInfoを再反映させる方法 RRS feed

  • 質問

  • WPFで複数タブの有る画面を作成しています。
    入力された値を元にチェックを行い、
    修正が必要な場合は、IDataErrorInfoを利用して
    エラー情報を各入力項目のtooltipに表示しています。
    (対象のフレームワークが.Net Framework4.0なので)

    値の変更時のエラーは間違いなく表示されますが、
    別のタブに切替えて、再度戻った時にはエラーの表記が消されてしまいます。

    エラーの発生しているタブに戻った場合に、エラーになった項目の変更通知を
    View側に発行すればいいのかと、RaisePropertyChangedのイベントを発行しても
    画面には反映されませんでした。
    IDataErrorInfoを再度反映させるにはどのような記述が必要でしょうか?
    2016年5月2日 4:41

回答

  • エラー表記というのはTextBoxに赤枠が出るようなことを指しているであれば、TabItemの中身の外側がAdornerDecoratorになるようにしてください。

    <Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
        <Grid>
            <TabControl>
                <TabItem Header="A" DataContext="{Binding [0],NotifyOnValidationError=true}">
                    <AdornerDecorator>
                        <StackPanel>
                            <TextBox Text="{Binding Text,ValidatesOnDataErrors=True,UpdateSourceTrigger=PropertyChanged}" Width="200">
                                <TextBox.ToolTip>
                                    <Binding Path="(Validation.Errors)[0].ErrorContent" 
                                         RelativeSource="{RelativeSource Mode=Self}"/>
                                </TextBox.ToolTip>
                            </TextBox>
                        </StackPanel>
                    </AdornerDecorator>
                </TabItem>
                <TabItem Header="B" DataContext="{Binding [1]}">
                    <AdornerDecorator>
                        <StackPanel>
                            <TextBox Text="{Binding Text,ValidatesOnDataErrors=True,UpdateSourceTrigger=PropertyChanged}" Width="200"/>
                        </StackPanel>
                    </AdornerDecorator>
                </TabItem>
            </TabControl>
    
        </Grid>
    </Window>
    
    Imports System.ComponentModel
    Class MainWindow
        Sub New()
    
            InitializeComponent()
            Dim list As New List(Of Item)
            list.Add(New Item() With {.Header = "Tab1"})
            list.Add(New Item() With {.Header = "Tab2"})
            Me.DataContext = list
        End Sub
    End Class
    
    Class Item
        Implements INotifyPropertyChanged
        Implements IDataErrorInfo
    
    
        Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
        Protected Overridable Sub OnPropertyChanged(ByVal name As String)
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(name))
        End Sub
    
        Private _errors As New Dictionary(Of String, String)
    
        Public ReadOnly Property [Error] As String Implements IDataErrorInfo.Error
            Get
                Return IIf(_errors.Count > 0, "ERROR", Nothing)
            End Get
        End Property
    
        Default Public ReadOnly Property Item(columnName As String) As String Implements IDataErrorInfo.Item
            Get
                Dim er As String = Nothing
                _errors.TryGetValue(columnName, er)
                Return er
            End Get
        End Property
    
        Public Property Text As String
            Get
                Return _Text
            End Get
            Set(value As String)
                _Text = value
                OnPropertyChanged("Text")
    
                If (_Text <> "123") Then
                    _errors("Text") = "out of range"
                Else
                    _errors.Remove("Text")
                End If
            End Set
        End Property
        Private _Text As String
    
        Public Property Header As String
    End Class
    


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 回答としてマーク WPF_Visiter 2016年5月2日 7:31
    2016年5月2日 6:43

すべての返信

  • エラー表記というのはTextBoxに赤枠が出るようなことを指しているであれば、TabItemの中身の外側がAdornerDecoratorになるようにしてください。

    <Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
        <Grid>
            <TabControl>
                <TabItem Header="A" DataContext="{Binding [0],NotifyOnValidationError=true}">
                    <AdornerDecorator>
                        <StackPanel>
                            <TextBox Text="{Binding Text,ValidatesOnDataErrors=True,UpdateSourceTrigger=PropertyChanged}" Width="200">
                                <TextBox.ToolTip>
                                    <Binding Path="(Validation.Errors)[0].ErrorContent" 
                                         RelativeSource="{RelativeSource Mode=Self}"/>
                                </TextBox.ToolTip>
                            </TextBox>
                        </StackPanel>
                    </AdornerDecorator>
                </TabItem>
                <TabItem Header="B" DataContext="{Binding [1]}">
                    <AdornerDecorator>
                        <StackPanel>
                            <TextBox Text="{Binding Text,ValidatesOnDataErrors=True,UpdateSourceTrigger=PropertyChanged}" Width="200"/>
                        </StackPanel>
                    </AdornerDecorator>
                </TabItem>
            </TabControl>
    
        </Grid>
    </Window>
    
    Imports System.ComponentModel
    Class MainWindow
        Sub New()
    
            InitializeComponent()
            Dim list As New List(Of Item)
            list.Add(New Item() With {.Header = "Tab1"})
            list.Add(New Item() With {.Header = "Tab2"})
            Me.DataContext = list
        End Sub
    End Class
    
    Class Item
        Implements INotifyPropertyChanged
        Implements IDataErrorInfo
    
    
        Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
        Protected Overridable Sub OnPropertyChanged(ByVal name As String)
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(name))
        End Sub
    
        Private _errors As New Dictionary(Of String, String)
    
        Public ReadOnly Property [Error] As String Implements IDataErrorInfo.Error
            Get
                Return IIf(_errors.Count > 0, "ERROR", Nothing)
            End Get
        End Property
    
        Default Public ReadOnly Property Item(columnName As String) As String Implements IDataErrorInfo.Item
            Get
                Dim er As String = Nothing
                _errors.TryGetValue(columnName, er)
                Return er
            End Get
        End Property
    
        Public Property Text As String
            Get
                Return _Text
            End Get
            Set(value As String)
                _Text = value
                OnPropertyChanged("Text")
    
                If (_Text <> "123") Then
                    _errors("Text") = "out of range"
                Else
                    _errors.Remove("Text")
                End If
            End Set
        End Property
        Private _Text As String
    
        Public Property Header As String
    End Class
    


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 回答としてマーク WPF_Visiter 2016年5月2日 7:31
    2016年5月2日 6:43
  • gekkaさん

    ありがとうございます。

    頂いた内容を元にサンプルで動作確認の後、適応した処

    あっさり解決できました。

    AdornerDecoratorというものをまったく知らなかったので、これから勉強致します。

    助かりました。ありがとうございました

    2016年5月2日 7:31