Как предотвратить DataGrid отсечения изображений, которые перекрывают верхний ряд? - PullRequest
0 голосов
/ 07 января 2019

У нас есть стандартный шаблон Validation.ErrorTemplate, который рисует красную рамку и отображает значок ошибки в верхнем правом углу элементов управления с ошибками проверки. Это прекрасно работает везде, кроме верхнего ряда сетки данных, где изображение обрезается с помощью (я думаю) ScrollViewer сетки.

Clipped error icon

В идеале верхний значок ошибки должен отображаться полностью, а нижний не должен отображаться до тех пор, пока эта строка не станет видимой.

Вот пример, который воспроизводит проблему в настолько малом количестве кода, насколько я могу управлять:

<Window x:Class="WpfClippedAdorner.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:draw="clr-namespace:System.Drawing;assembly=System.Drawing"
    xmlns:valueConverters="clr-namespace:WpfClippedAdorner.ValueConverters"
    mc:Ignorable="d"
    Title="MainWindow" Height="150" Width="200">
<Grid>
    <Grid.Resources>
        <valueConverters:IconToImageSourceConverter x:Key="IconToImageSourceConverter" />
    </Grid.Resources>
    <DataGrid AutoGenerateColumns="False" Height="75" Width="150" 
              ClipToBounds="False">
        <DataGrid.Columns>
            <DataGridTemplateColumn>
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <DockPanel LastChildFill="true">
                            <Border BorderBrush="red" BorderThickness="1" >
                                <TextBlock Text="{Binding Text}" />
                            </Border>
                            <Image Source="{Binding Source={x:Static draw:SystemIcons.Error}, Converter={StaticResource IconToImageSourceConverter}, Mode=OneWay}" 
                                   Margin="-10,-8,0,0" Height="16" Width="16" VerticalAlignment="Top"/>
                        </DockPanel>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>
        <DataGrid.Items>
            <TextBlock Text="Test1"/>
            <TextBlock Text="Test2"/>
            <TextBlock Text="Test3"/>
            <TextBlock Text="Test4"/>
        </DataGrid.Items>
    </DataGrid>
</Grid>
</Window>

Обратите внимание, что ClipToBounds имеет значение False, но не решает проблему. Я также попытался извлечь шаблон элемента управления DataGrid и установить везде ClipToBounds = "False" без видимого эффекта.

Вот конвертер значений, который я использовал для отображения значка на тот случай, если вы захотите воссоздать мой тестовый проект.

namespace WpfClippedAdorner.ValueConverters
{
using System;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;

/// <summary>
/// Converts a windows icon to an image source that can be used in WPF
/// </summary>
/// <seealso cref="System.Windows.Data.IValueConverter" />
public class IconToImageSourceConverter : IValueConverter
{
    /// <inheritdoc />
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var icon = value as Icon;
        if (icon == null)
        {
            Trace.TraceWarning("Attempted to convert {0} instead of Icon object in IconToImageSourceConverter", value);
            return null;
        }

        ImageSource imageSource = Imaging.CreateBitmapSourceFromHIcon(
            icon.Handle,
            Int32Rect.Empty,
            BitmapSizeOptions.FromWidthAndHeight(16, 16));
        return imageSource;
    }

    /// <inheritdoc />
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
}

Наконец, вот фактический стиль, который мы используем для выделения ошибок валидации, на случай, если я допустил ошибки в его упрощении.

<Style x:Key="ErrorDisplay" TargetType="FrameworkElement">
    <Setter Property="Margin" Value="5,5,5,5" />
    <Setter Property="Validation.ErrorTemplate">
        <Setter.Value>
            <ControlTemplate>
                <DockPanel LastChildFill="true">
                    <AdornedElementPlaceholder Name="customAdorner" VerticalAlignment="Center" >
                        <Border BorderBrush="red" BorderThickness="1" />
                    </AdornedElementPlaceholder>
                    <Image Source="{Binding Source={x:Static draw:SystemIcons.Error}, Converter={StaticResource IconToImageSourceConverter}, Mode=OneWay}" 
                           Margin="-10,-8,0,0" Height="16" Width="16" VerticalAlignment="Top"
                           ToolTip="{Binding ElementName=customAdorner, Path=AdornedElement.(Validation.Errors).CurrentItem.ErrorContent}"/>
                </DockPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Style.Triggers>
        <Trigger Property="Validation.HasError" Value="True">
            <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors).CurrentItem.ErrorContent}" />
        </Trigger>
    </Style.Triggers>
</Style>
...