5

TextBox と ComboBox を含む複数のコントロールがあり、Validation.Errors コレクションに含まれるすべてのエラーを含むツールヒントをすべてのコントロールに表示したいと考えています。できれば全員に共通のスタイルを共有してもらいたいと思っており、それが私が試みていることです。ToolTip セッターのバインディングに何か問題があると確信していますが、何が原因かわかりません。エラーの重大度 (エラーまたは警告) を指定する INotifyDataErrorInfo 実装で Error オブジェクトを返します。

ウィンドウ内のすべてのコントロールに適用され、そのコントロールのすべてのエラーと警告のリストを含むツールヒントを表示するスタイルが必要です。エラーは赤で、警告は黄色で表示されます。これが私が思いついたスタイルです:

        <Style TargetType="FrameworkElement">
        <Setter Property="ToolTip">
            <Setter.Value>
                <ItemsControl ItemsSource="{Binding Path=(Validation.Errors), RelativeSource={RelativeSource Self}}">
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding ErrorContent.ErrorMessage}">
                                <TextBlock.Style>
                                    <Style TargetType="TextBlock">
                                        <Setter Property="Foreground" Value="Red"/>
                                        <Style.Triggers>
                                            <DataTrigger Binding="{Binding ErrorContent.ErrorSeverity}"
                                                             Value="{x:Static local:ErrorType.Warning}">
                                                <Setter Property="Foreground" Value="Yellow"/>
                                            </DataTrigger>
                                        </Style.Triggers>
                                    </Style>
                                </TextBlock.Style>
                            </TextBlock>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
            </Setter.Value>
        </Setter>
        <Style.Triggers>
            <DataTrigger Binding="{Binding Path=(Validation.HasError)}" Value="True">
                <Setter Property="ToolTip">
                    <Setter.Value>
                        <ItemsControl ItemsSource="{Binding Path=(Validation.Errors)}">
                            <ItemsControl.ItemTemplate>
                                <DataTemplate>
                                    <TextBlock Text="{Binding ErrorContent.ErrorMessage}">
                                        <TextBlock.Style>
                                            <Style TargetType="TextBlock">
                                                <Setter Property="Foreground" Value="Red"/>
                                                <Style.Triggers>
                                                    <DataTrigger Binding="{Binding ErrorContent.ErrorSeverity}"
                                                             Value="{x:Static local:ErrorType.Warning}">
                                                        <Setter Property="Foreground" Value="Yellow"/>
                                                    </DataTrigger>
                                                </Style.Triggers>
                                            </Style>
                                        </TextBlock.Style>
                                    </TextBlock>
                                </DataTemplate>
                            </ItemsControl.ItemTemplate>
                        </ItemsControl>
                    </Setter.Value>
                </Setter>
            </DataTrigger>
        </Style.Triggers>
    </Style>

RelativeSource を変更して、AncestorLevel 1 と 2 の両方で Control の AncestoryType を検索しようとしましたが、どれもうまくいかないようです。

ほとんど同じことを行う ErrorTemplate に使用した ControlTemplate に基づいてスタイルを作成しました。エラーの重大度に応じて赤または黄色の境界線を表示し、コントロールの ToolTip に対してやりたいこととまったく同じように ToolTip を表示します。自体。ErrorTemplate の DataContext が自動的に Validation.Errors コレクションに設定され、ItemsSource を ItmesCollection にバインドしやすくなるため、バインディングに何らかの関係があると確信しています。スタイルのツールチップにはそのような運はありません。これが、ErrorTemplate に使用した実際の ControlTemplate です。

        <ControlTemplate x:Key="ErrorTemplate">
        <Border BorderThickness="1">
            <AdornedElementPlaceholder Name="ElementPlaceholder"/>
            <Border.Style>
                <Style TargetType="Border">
                    <Setter Property="BorderBrush" Value="Red"/>
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding ElementName=ElementPlaceholder, Path=AdornedElement.(Validation.Errors)[0].ErrorContent.ErrorSeverity}"
                                         Value="{x:Static local:ErrorType.Warning}">
                            <Setter Property="BorderBrush" Value="Yellow"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </Border.Style>
            <Border.ToolTip>
                <ItemsControl ItemsSource="{Binding}">
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding ErrorContent.ErrorMessage}">
                                <TextBlock.Style>
                                    <Style TargetType="TextBlock">
                                        <Setter Property="Foreground" Value="Red"/>
                                        <Style.Triggers>
                                            <DataTrigger Binding="{Binding ErrorContent.ErrorSeverity}"
                                                             Value="{x:Static local:ErrorType.Warning}">
                                                <Setter Property="Foreground" Value="Yellow"/>
                                            </DataTrigger>
                                        </Style.Triggers>
                                    </Style>
                                </TextBlock.Style>
                            </TextBlock>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
            </Border.ToolTip>
        </Border>
    </ControlTemplate>

誰でも私に何か提案をしてもらえますか?

4

3 に答える 3

9

これは、はるかに簡単に実現できます。

上記のように "Tooltip" へのバインドを記述した場合:

<Trigger Property="Validation.HasError" Value="True">
      <Setter Property="ToolTip"
              Value="{Binding RelativeSource={RelativeSource Self},  Path=(Validation.Errors), Converter={StaticResource ErrorCollectionConverter}}">
      </Setter>
</Trigger>

バインディングは「奇跡的に」実際にツールチップの「PlacementTarget」に再バインドします。このようにコントロールに取り付けられます。

アイテムの完全なリストを表示する必要がある場合は、以下を実行できます。

<Trigger Property="Validation.HasError" Value="True">
      <Setter Property="ToolTip">
          <Setter.Value>
               <ToolTip DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget}">
                   <ItemsControl ItemsSource="{Binding Path=(Validation.Errors)}" DisplayMemberPath="ErrorContent" />
               </ToolTip>
          </Setter.Value>
      </Setter>
</Trigger>

Tooltip オブジェクトをドロップして、ItemsControl から PlacementTarget に直接バインドすることもできます。次に、ItemsControl の AncestorType を介して Tooltip を RelativeSource として使用します。

お役に立てれば :)

于 2015-08-28T13:05:59.137 に答える
5

かなり長い間これを理解しようとした後、私は最終的に正しい道をたどるMSDN フォーラムの投稿に出くわしました。まず、必要な各 TargetType のスタイルを指定し、元のスタイルに基づいて作成する必要がありました。次に、問題はバインディングにあるのではなく、バインドされているコレクションが更新されていないことに気付きました。XAML で指定したときに ListBox/ItemsControl が更新されなかった理由はわかりませんが、コンバーターで指定すると機能します。ここに私の新しいスタイルがあります:

        <Style TargetType="Control" x:Key="ErrorToolTip">
        <Style.Resources>
            <Style TargetType="ListBoxItem">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate>
                            <TextBlock Text="{Binding ErrorContent.ErrorMessage}"
                                       Background="Transparent">
                                <TextBlock.Style>
                                    <Style TargetType="TextBlock">
                                        <Setter Property="Foreground" Value="Red"/>
                                        <Style.Triggers>
                                            <DataTrigger Binding="{Binding ErrorContent.ErrorSeverity}"
                                                         Value="{x:Static local:ErrorType.Warning}">
                                                <Setter Property="Foreground" Value="Orange" />
                                            </DataTrigger>
                                        </Style.Triggers>
                                    </Style>
                                </TextBlock.Style>
                            </TextBlock>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Style.Resources>
        <Style.Triggers>
            <Trigger Property="Validation.HasError" Value="True">
                <Setter Property="ToolTip"
                        Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors), Converter={StaticResource ErrorCollectionConverter}}">
                </Setter>
            </Trigger>
        </Style.Triggers>
    </Style>
    <Style TargetType="TextBox" BasedOn="{StaticResource ErrorToolTip}"/>
    <Style TargetType="ComboBox" BasedOn="{StaticResource ErrorToolTip}"/>

そして、ここに私のコンバーター関数があります:

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null) return null;
        return new ListBox
        {
            ItemsSource = (ReadOnlyObservableCollection<ValidationError>) value,
            BorderThickness = new Thickness(0),
            Background = Brushes.Transparent
        };
    }

これが、私と同じ問題を抱えている他の人に役立つことを願っています. なぜこれが大きな違いを生むのか誰かが知っているなら、私は知りたい.

于 2014-04-07T18:56:43.427 に答える
2

これは、私が使用したマットの回答の単純化されたバージョンです。タイプのコントロールに対してのみ機能しTextBox、エラーの重大度は使用しません。ユーザーが入力したディレクトリ パスのコンテキストで 1 つ以上のエラーを表示する必要がある場合に使用しました。Matts の回答とは対照的に、 DisplayMemberPath = "ErrorContent" を使用して、コンバーターで直接エラーにアクセスしました。


TextBox添付プロパティValidation.HasErrorが trueの場合にツールチップを表示 する のスタイル:

<UserControl.Resources>
    <ui:ErrorCollectionConverter x:Key="ErrorCollectionConverter"></ui:ErrorCollectionConverter>
    <Style TargetType="TextBox">
        <Style.Triggers>
            <Trigger Property="Validation.HasError" Value="True">
                <Setter Property="ToolTip"
                    Value="{Binding RelativeSource={RelativeSource Self},  Path=(Validation.Errors), Converter={StaticResource ErrorCollectionConverter}}">
                </Setter>
            </Trigger>
        </Style.Triggers>
    </Style>
</UserControl.Resources>

TextBoxスタイルを暗黙的に使用する私の「ディレクトリ」 :

<TextBox Text="{Binding Directory, UpdateSourceTrigger=PropertyChanged, ValidatesOnNotifyDataErrors=True}"></TextBox>

ErrorContentプロパティに直接アクセスする値コンバーター:

internal class ErrorCollectionConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null) return null;
        return new ListBox
        {
            ItemsSource = (ReadOnlyObservableCollection<ValidationError>)value,
            BorderThickness = new Thickness(0),
            Background = Brushes.Transparent,
            DisplayMemberPath = "ErrorContent"
        };
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}   
于 2015-08-12T14:59:05.173 に答える