web-dev-qa-db-ja.com

ツールチップで検証エラーを表示するWPFスタイルがTextBoxで機能するのにComboBoxで失敗するのはなぜですか?

以下に示すように、典型的なスタイルを使用して、検証エラーをテキストボックスのIErrorDataInfoからのツールチップとして表示していますが、正常に動作します。

    <Style TargetType="{x:Type TextBox}">
        <Style.Triggers>
            <Trigger Property="Validation.HasError" Value="true">
                <Setter Property="ToolTip"
                Value="{Binding RelativeSource={RelativeSource Self},
            Path=(Validation.Errors)[0].ErrorContent}"/>
            </Trigger>
        </Style.Triggers>
    </Style>

しかし、私がこのようなComboBoxに対して同じことを行おうとすると、失敗します

    <Style TargetType="{x:Type ComboBox}">
        <Style.Triggers>
            <Trigger Property="Validation.HasError" Value="true">
                <Setter Property="ToolTip"
                Value="{Binding RelativeSource={RelativeSource Self},
            Path=(Validation.Errors)[0].ErrorContent}"/>
            </Trigger>
        </Style.Triggers>
    </Style>

出力ウィンドウに表示されるエラーは次のとおりです。

System.Windows.Data Error:17: '(Validation.Errors)'(タイプ 'ReadOnlyObservableCollection`1')から 'Item []'値(タイプ 'ValidationError')を取得できません。BindingExpression:Path =(0 )[0] .ErrorContent; DataItem = 'ComboBox'(Name = 'ownerComboBox');ターゲット要素は 'ComboBox'(Name = 'ownerComboBox');ターゲットプロパティは 'ToolTip'(type 'Object')ArgumentOutOfRangeException: 'System .ArgumentOutOfRangeException:指定された引数は有効な値の範囲外でした。パラメーター名:index '

奇妙なことに、ComboBoxの値を変更した場合、ウィンドウを閉じるときに無効なデータベースの変更も試みます(これは、バインディングエラーが発生した場合でも発生します)!!!

値NULLを列 'EmpFirstName'、テーブル 'OITaskManager.dbo.Employees'に挿入できません。列はnullを許可しません。INSERTは失敗します。ステートメントは終了しました。

スタイルをコメントアウトするだけで、すべてが完璧に機能します。どうすれば修正できますか?

誰かがそれを必要とする場合に備えて、comboBoxのxamlの1つは次のとおりです。

<ComboBox ItemsSource="{Binding Path=Employees}" 
                  SelectedValuePath="EmpID"                       
                  SelectedValue="{Binding Path=SelectedIssue.Employee2.EmpID,
                     Mode=OneWay, ValidatesOnDataErrors=True}" 
                  ItemTemplate="{StaticResource LastNameFirstComboBoxTemplate}"
                  Height="28" Name="ownerComboBox" Width="120" Margin="2" 
                  SelectionChanged="ownerComboBox_SelectionChanged" />


<DataTemplate x:Key="LastNameFirstComboBoxTemplate">
    <TextBlock> 
         <TextBlock.Text> 
             <MultiBinding StringFormat="{}{1}, {0}" > 
                   <Binding Path="EmpFirstName" /> 
                   <Binding Path="EmpLastName" /> 
             </MultiBinding>
         </TextBlock.Text>
    </TextBlock>
</DataTemplate>

SelectionChanged:(まもなくコマンドを実装する予定ですが、これは私の最初のWPFプロジェクトなので、まだ完全なMVVMに移行していません。中小規模のバイトで物事を進めようとしています)

// This is done this way to maintain the DataContext Integrity 
// and avoid an error due to an Object being "Not New" in Linq-to-SQL
private void ownerComboBox_SelectionChanged(object sender, 
                                            SelectionChangedEventArgs e)
{
    Employee currentEmpl = ownerComboBox.SelectedItem as Employee;
    if (currentEmpl != null && 
        currentEmpl != statusBoardViewModel.SelectedIssue.Employee2)
    {
        statusBoardViewModel.SelectedIssue.Employee2 = currentEmpl;
    }
}
40
Mike B

このエラーが発生するのは、検証により問題がないことが判明した場合、Errorsコレクションがアイテムなしで返され、次のバインディングロジックが失敗するためです。

Path=(Validation.Errors)[0].ErrorContent}"

特定のインデックスで検証コレクションにアクセスしている。現在、このテキストを置き換えるためのDataTemplate Suggestionに取り組んでいます。

Microsoftがこれを検証テンプレートの標準的な例にリストしたことを気に入っています。

updateしたがって、上記のコードを次のコードに置き換えます。そうすると、バインディングロジックは空のvalidationresultコレクションを処理する方法を認識します。

Path=(Validation.Errors).CurrentItem.ErrorContent}"

(以下のxamlがコメントとして追加されました)

<ControlTemplate x:Key="ValidationErrorTemplate" TargetType="Control">
    <StackPanel Orientation="Horizontal">
        <TextBlock Foreground="Red" FontSize="24" Text="*" 
                   ToolTip="{Binding .CurrentItem}">
        </TextBlock>
        <AdornedElementPlaceholder>
        </AdornedElementPlaceholder>
    </StackPanel>
</ControlTemplate>

2019年に更新

現在のところ、使用する正しいパス構文は次のとおりです。

Path=(Validation.Errors)/ErrorContent
109

私はこれが最良の方法だと思います:

Path=(Validation.Errors)/ErrorContent

/は実際には@NathanによるCurrentItemと等しい

私の場合、CurrentItemは大丈夫です。

12
Altiano Gerung

説明されているように、複数行の文字列に変換するためのコンバータを試してください ここ

2
djamwal

私の場合、適用しようとしたときにこの例外が発生しました @ Nation Tregillus 'ソリューション:

タイプ「System.Collections.ObjectModel.ReadOnlyObservableCollection」のデータコンテキストでプロパティ「CurrentItem」を解決できません

したがって、代わりに @ Altiano Gerung の解決策を使用しましたが、私のコードは次のようになります。

<ControlTemplate x:Key="ValidationErrorTemplate">
    <DockPanel Margin="5,0,36,0">
        <StackPanel Orientation="Horizontal" VerticalAlignment="Top" DockPanel.Dock="Right"
                    Margin="5,0,36,0"
                    ToolTip="{Binding ElementName=ErrorAdorner, Path=AdornedElement.(Validation.Errors)/ErrorContent}"
                    ToolTipService.ShowDuration="300000"
                    ToolTipService.InitialShowDelay="0"
                    ToolTipService.BetweenShowDelay="0"
                    ToolTipService.VerticalOffset="-75"
                    >
1
user8128167

あなたが使用しているコードが複数の場所に投稿されているのを見ましたが、私には奇妙に思えます

Path=(Validation.Errors)[0].ErrorContent}

赤旗を上げません。しかし、私はWPFにも不慣れです。おそらく、すべての場合にそれを機能させる秘訣があるでしょう。

空の可能性があるコレクションに配列インデックスを使用してインデックスを作成するのではなく、リストの最初のエラーを返すコンバーターを追加します。

1
David

CurrentItemも機能しませんでしたが、@ Nathtanの回答は、カスタムtextBoxリソースがある状況で機能しました。 @Nathanに感謝します。これに1時間費やしました。

<Style.Triggers>
  <Trigger Property="Validation.HasError" Value="true">
    <Setter Property="ToolTip"
        Value="{Binding RelativeSource={x:Static RelativeSource.Self},
        Path=(Validation.Errors)/ErrorContent}" />
  </Trigger>
</Style.Triggers>
0
bbedson