【问题标题】:WPF: Show validation Tooltip in DataGridComboBoxColumnWPF:在 DataGridComboBoxColumn 中显示验证工具提示
【发布时间】:2017-06-17 20:46:55
【问题描述】:

我有一个包含多个 ComboBox 列的 DataGrid。使用 ViewModel 中的 IDataErrorInfo 接口验证这些值。将鼠标悬停在相应的单元格上时,工具提示应显示验证错误。

实现此行为的正常方法是使用 ElementStyle,如下所示:

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

这适用于 DataGridTextColumns,但 不适用于 DataGridComboBoxColumns(不显示工具提示)。如果 EditingElementStyle 使用相同的代码,则一切正常。但仅当单元格处于编辑模式时(如预期的那样,因为 EditingElementStyle 仅在编辑模式下使用)。

在 WWW 上找到的这个问题的解决方案推荐使用这样的 CellStyle:

<DataGridComboBoxColumn ...>
  <DataGridComboBoxColumn.CellStyle>
    <Style TargetType="DataGridCell">
      <Style.Triggers>
        <DataTrigger Binding="{Binding Path=(Validation.HasError), RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridRow}}}" 
                     Value="True">
          <Setter Property="ToolTip"
                            Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridRow}}, Path=(Validation.Errors)[0].ErrorContent}" />
        </DataTrigger>
      </Style.Triggers>
    </Style>
  </DataGridComboBoxColumn.CellStyle>
</DataGridComboBoxColumn>

此方法使用 DataGridRow 和硬编码索引来获取错误。这对我来说似乎很容易出错。无论如何,只要行中只有一个验证错误,它就应该工作。但是一旦同一行中有两个或更多验证错误,它就不再起作用了。每个工具提示都会显示第一个验证错误(因为硬编码索引):

所以我很自然地使用 DataGridCell 而不是 DataGridRow 来获取错误(请参阅下面绑定中的 RelativeSource):

<DataGridComboBoxColumn ...>
  <DataGridComboBoxColumn.CellStyle>
    <Style TargetType="DataGridCell">
      <Style.Triggers>
        <DataTrigger Binding="{Binding Path=(Validation.HasError), RelativeSource={RelativeSource Self}}" 
                     Value="True">
          <Setter Property="ToolTip"
                            Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" />
        </DataTrigger>
      </Style.Triggers>
    </Style>
  </DataGridComboBoxColumn.CellStyle>
</DataGridComboBoxColumn>

但是使用这种样式,没有显示工具提示。输出窗口中没有错误或警告。将 PresentationTraceSources.TraceLevel=High 添加到触发器绑定表明 HasError 属性返回 false。

移除 Tooltip 绑定周围的触发器时,Validation.Errors 似乎不包含任何值:

System.Windows.Data Warning: 56 : Created BindingExpression (hash=13069983) for Binding (hash=50848483)
System.Windows.Data Warning: 58 :   Path: '(0)[0].ErrorContent'
System.Windows.Data Warning: 60 : BindingExpression (hash=13069983): Default mode resolved to OneWay
System.Windows.Data Warning: 61 : BindingExpression (hash=13069983): Default update trigger resolved to PropertyChanged
System.Windows.Data Warning: 62 : BindingExpression (hash=13069983): Attach to System.Windows.Controls.DataGridCell.ToolTip (hash=21168757)
System.Windows.Data Warning: 67 : BindingExpression (hash=13069983): Resolving source 
System.Windows.Data Warning: 70 : BindingExpression (hash=13069983): Found data context element: <null> (OK)
System.Windows.Data Warning: 72 :   RelativeSource.Self found DataGridCell (hash=21168757)
System.Windows.Data Warning: 78 : BindingExpression (hash=13069983): Activate with root item DataGridCell (hash=21168757)
System.Windows.Data Warning: 108 : BindingExpression (hash=13069983):   At level 0 - for DataGridCell.(Validation.Errors) found accessor DependencyProperty(Errors)
System.Windows.Data Warning: 104 : BindingExpression (hash=13069983): Replace item at level 0 with DataGridCell (hash=21168757), using accessor DependencyProperty(Errors)
System.Windows.Data Warning: 101 : BindingExpression (hash=13069983): GetValue at level 0 from DataGridCell (hash=21168757) using DependencyProperty(Errors): ReadOnlyObservableCollection`1 (hash=51278326 Count=0)
System.Windows.Data Warning: 109 : BindingExpression (hash=13069983):   At level 1 - for ReadOnlyObservableCollection`1[] found accessor RuntimePropertyInfo(Item)
System.Windows.Data Warning: 104 : BindingExpression (hash=13069983): Replace item at level 1 with ReadOnlyObservableCollection`1 (hash=51278326 Count=0), using accessor RuntimePropertyInfo(Item)
System.Windows.Data Warning: 101 : BindingExpression (hash=13069983): GetValue at level 1 from ReadOnlyObservableCollection`1 (hash=51278326 Count=0) using RuntimePropertyInfo(Item): {IListIndexOutOfRange}
System.Windows.Data Error: 17 : Cannot get 'Item[]' value (type 'ValidationError') from '(Validation.Errors)' (type 'ReadOnlyObservableCollection`1'). BindingExpression:Path=(0)[0].ErrorContent; DataItem='DataGridCell' (Name=''); target element is 'DataGridCell' (Name=''); target property is 'ToolTip' (type 'Object') ArgumentOutOfRangeException:'System.ArgumentOutOfRangeException: Das angegebene Argument liegt außerhalb des gültigen Wertebereichs.
Parametername: index'
System.Windows.Data Warning: 103 : BindingExpression (hash=13069983): Replace item at level 2 with {NullDataItem}
System.Windows.Data Warning: 80 : BindingExpression (hash=13069983): TransferValue - got raw value {DependencyProperty.UnsetValue}
System.Windows.Data Warning: 88 : BindingExpression (hash=13069983): TransferValue - using fallback/default value <null>
System.Windows.Data Warning: 89 : BindingExpression (hash=13069983): TransferValue - using final value <null>

有人有解决这个问题的方法吗?

【问题讨论】:

    标签: wpf


    【解决方案1】:

    有人有解决这个问题的办法吗?

    您为什么不简单地将DataGridComboBoxColumn 替换为DataGridTemplateColumn 并在CellTemplate 中使用TextBlock 并在CellEditingTemplate 中使用ComboBox?

    更灵活,结果完全相同。最重要的是,它实际上解决了您的问题:

    <DataGridTemplateColumn Header="...">
        <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Name, ValidatesOnDataErrors=True}">
                    <TextBlock.Style>
                        <Style TargetType="TextBlock">
                            <Style.Triggers>
                                <Trigger Property="Validation.HasError" Value="true">
                                    <Setter Property="ToolTip" Value="{Binding (Validation.Errors)[0].ErrorContent, RelativeSource={RelativeSource Self}}"/>
                                </Trigger>
                            </Style.Triggers>
                        </Style>
                    </TextBlock.Style>
                </TextBlock>
            </DataTemplate>
        </DataGridTemplateColumn.CellTemplate>
        <DataGridTemplateColumn.CellEditingTemplate>
            <DataTemplate>
                <ComboBox ItemsSource="{Binding SomeItems, RelativeSource={RelativeSource AncestorType=Window}}"
                                          SelectedItem="{Binding Name, ValidatesOnDataErrors=True}">
                    <ComboBox.Style>
                        <Style TargetType="ComboBox">
                            <Style.Triggers>
                                <Trigger Property="Validation.HasError" Value="true">
                                    <Setter Property="ToolTip" Value="{Binding (Validation.Errors)[0].ErrorContent, RelativeSource={RelativeSource Self}}"/>
                                </Trigger>
                            </Style.Triggers>
                        </Style>
                    </ComboBox.Style>
                </ComboBox>
            </DataTemplate>
        </DataGridTemplateColumn.CellEditingTemplate>
    </DataGridTemplateColumn>
    

    当 DataGridComboBoxColumn 处于只读模式时,不会显示“真正的”ComboBox。

    【讨论】:

    • 我目前正在尝试覆盖 DataGridComboBoxColum.GenerateElement() 以将 TextBlockComboBox 替换为 TextBlock。这与您的方法基本相同。这一点都不容易,因为我们也在使用 SelectedValuePath 和 DisplayMemberPath。
    • 你为什么要创建一个自定义类并重写 GenerateElement() 方法只是为了用 TextBlock 替换 ComboBox?这没有任何意义。按照我在回答中的建议使用 DataGridTemplateColumn。
    • 好的,但这与您关于工具提示的原始问题有何关系?
    • 我们正在使用从 DataGridComboBoxColumn 派生的自定义 DataGridColumn,包括一些自定义。我在上面的代码中使用了普通的 DataGridComboBoxColumn,因为那里也出现了工具提示问题。我们的自定义 DataGridColumn 与此无关。
    • 我将此标记为答案,因为它解决了一般问题。如果涉及 SelectedValuePath 和 DisplayMemberPath 之类的东西,事情就会变得更加复杂。但这为我指明了正确的方向。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-04
    • 2011-11-22
    • 1970-01-01
    • 2014-12-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多