I'm working on a custom WPF control that should visualize thousands of graphical primitives in a scrollable area. The core part of the control's template is the following:
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ItemVisualizer}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<local:ItemAreaElement Grid.Row="0" Grid.Column="0" x:Name="PART_ItemArea" />
<ScrollBar Grid.Row="0" Grid.Column="1" x:Name="PART_ScrollBarVert" Orientation="Vertical" Maximum="100" />
<ScrollBar Grid.Row="1" Grid.Column="0" x:Name="PART_ScrollBarHorz" Orientation="Horizontal" Maximum="100" />
<Rectangle Grid.Row="1" Grid.Column="1" x:Name="PART_SizeGrip" Focusable="False" Fill="#F0F0F0" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
For better performance, all drawing operations are performed in the OnRender method of the ItemAreaElement. To have crisp drawing, I also use the following setting in the initialization code:
this.SetValue(RenderOptions.EdgeModeProperty, EdgeMode.Aliased);
However, I have some strange issues with my drawing. To demonstrate them, I simplified the definition of my ItemAreaElement to the following:
class ItemAreaElement : FrameworkElement
{
protected override void OnRender(DrawingContext drawingContext)
{
base.OnRender(drawingContext);
const int ITEM_WIDTH = 60;
const int ITEM_HEIGHT = 20;
Pen penRed = new Pen(Brushes.Red, 1);
Pen penGreen = new Pen(Brushes.Green, 1);
int y = 0;
for (int iRow = 0; iRow < 3; iRow++)
{
int x = 0;
for (int iCol = 0; iCol < 2; iCol++)
{
Point cornerTopLeft = new Point(x, y);
dc.DrawLine(penRed, cornerTopLeft, new Point(x + ITEM_WIDTH - 1, y));
dc.DrawLine(penRed, cornerTopLeft, new Point(x, y + ITEM_HEIGHT - 1));
Point cornerBottomRight = new Point(x + ITEM_WIDTH - 1, y + ITEM_HEIGHT - 1);
dc.DrawLine(penGreen, new Point(x + ITEM_WIDTH - 1, y), cornerBottomRight);
dc.DrawLine(penGreen, new Point(x, y + ITEM_HEIGHT - 1), cornerBottomRight);
x += ITEM_WIDTH;
}
y += ITEM_HEIGHT;
}
}
}
When I launch this code on my main dev laptop equipped with an Ultra-HD screen with 282ppi (the system scale factor is 300%), I get this picture:
Or, after zooming in paint.net with gridlines:
As you see, the left, and top edges of my ItemAreaElement are partially covered by the border of the control. Must it be so? Is there a setting I can use to avoid this?
The second problem are lines that do not include the start point (see the top-left corner of my "cells"). Is this the expected behavior? IF so, how to force WPF to draw the start pixel?
And the third problem is the place or device-independent point in which the green lines should meet (the bottom-right corner of my cells). As you can see, this point is jagged. I expected to see just a green square in that place. Can I implement this with the help of the DrawingContext.DrawLine method? Or do I need to use a more complex geometry with special settings for multi-point lines, etc.?
By the way, when I launch this code on a test pc with a "classic" 96 ppi monitor and the scale factor of the OS set to 100%, the situation is a little bit better in the bottom-right corner:
But I even do not see the horizontal red lines in the top row or vertical red lines in the first column. I expected to see them there but not to be covered by the control's border.



I've managed to solve all my problems by setting the corresponding guidelines. Below you'll find the improved version of the OnRender() method presented above: