中等(125%)显示器上WPF DataGrid中缺少边框线

中等(125%)显示器上WPF DataGrid中缺少边框线,wpf,datagrid,Wpf,Datagrid,我在Win7上的wpf DataGrid出现了一个奇怪的渲染问题,显示设置为“中等”-125%。第2列和第3列之间预期的黑色垂直边界线不可见 <DataGrid ItemsSource="{Binding Rows}" AutoGenerateColumns="False"> <DataGrid.Resources> <Style TargetType="DataGridCell" >

我在Win7上的wpf DataGrid出现了一个奇怪的渲染问题,显示设置为“中等”-125%。第2列和第3列之间预期的黑色垂直边界线不可见

<DataGrid ItemsSource="{Binding Rows}" AutoGenerateColumns="False">
            <DataGrid.Resources>
                <Style TargetType="DataGridCell" >
                    <Setter Property="Background" Value="Orange"></Setter>
                    <Setter Property="BorderThickness" Value="0"></Setter>
                </Style>
            </DataGrid.Resources>
            <DataGrid.Columns>
                <DataGridTextColumn></DataGridTextColumn>
                <DataGridTextColumn  Width="150" ></DataGridTextColumn>
                <DataGridTextColumn></DataGridTextColumn>
            </DataGrid.Columns>
        </DataGrid>

这是我能重现问题的最简单的代码。可以使用任何viewmodel查看此问题。
例如,将宽度从150更改为150.1可以修复此问题。你们能给我解释一下发生了什么吗?如何避免这种情况发生?

问题在于
DataGrid
如何计算每列的位置和大小。简单示例:当您将
DataGridColumn
Width
设置为95.0时,实际渲染的列数为95.2;但是,
DataGrid
将使用95.0计算列X位置,而不是95.2

这种差异表现在某些列上缺少边框,因为下一列由于缺少小数部分而将上一列的空间“吞噬”了一个像素

解决方案是为
DataGridColumn
设置正确的
宽度
,使其与渲染宽度完全相同。在这种情况下,
DataGrid
意识到了小数部分,所有的边框都将就位

在渲染列之前,可以使用下面的代码以“DPI感知”的方式计算列的宽度。我不为代码申请积分,因为我是从这里得到的


您是否尝试过应用UseLayoutRounding或SnapToDevicePixels,看看它是否解决了问题?使用这两种方法中的任何一种都会迫使WPF将内容排列到最近的像素。我认为125%的设置可能会在渲染中造成一些重叠。我尝试在DataGrid上应用,并在DataGridCell的样式中进行设置。他们都没帮上忙,都有同样的问题。似乎下一列“吞噬”上一列,而边框重叠,因此变得不可见。
var dpiProperty = typeof(SystemParameters).GetProperty("Dpi", BindingFlags.NonPublic | BindingFlags.Static);
var dpi = (int)dpiProperty.GetValue(null, null);
var pixelSize = 96.0 / dpi;

foreach (var dataGridColumn in this.DataGrid.Columns)
{
    var actualColumnWidth = dataGridColumn.Width.DisplayValue + (pixelSize / 2);
    var div = (actualColumnWidth * 1000) / (pixelSize * 1000);
    actualColumnWidth = (int)div * pixelSize;

    dataGridColumn.Width = new DataGridLength(actualColumnWidth, DataGridLengthUnitType.Pixel);
}