我正在處理一個自定義的WPF控件,該控件應該可視化可滾動區域中的數千個圖形基元。該控件的模板的核心部分如下:WPF中DrawingContext的奇怪繪圖
<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>
爲了提高性能,所有的繪圖操作在ItemAreaElement的方法的OnRender進行。有清脆的圖紙,我也用以下設置在初始化代碼:
this.SetValue(RenderOptions.EdgeModeProperty, EdgeMode.Aliased);
不過,我有一些奇怪的問題,與我的圖紙。爲了證明他們,我簡化我的ItemAreaElement的定義如下:
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;
}
}
}
當我在我的主要dev的筆記本電腦配備了超高清屏幕,282ppi(系統比例係數爲300%),啓動此代碼,我得到這樣的畫面:
或者,在paint.net與網格線變焦後:
如您所見,我的ItemAreaElement的左邊和頂邊部分由控件的邊框覆蓋。一定是這樣嗎?有沒有我可以用來避免這種情況的設置?
第二個問題是行不包括起點(請參閱我的「單元格」的左上角)。這是預期的行爲?如果是這樣,如何強制WPF繪製起始像素?
第三個問題是綠線應該符合的位置或與設備無關的點(我的細胞的右下角)。正如你所看到的,這一點是鋸齒狀的。我期望在那個地方看到一個綠色的廣場。我可以在DrawingContext.DrawLine方法的幫助下實現這個嗎?或者,我是否需要使用更復雜的幾何體以及多點線等的特殊設置?
順便說一句,當我在具有「經典」96 ppi顯示器並且操作系統的比例因子設置爲100%的測試電腦上啓動此代碼時,右下角的情況稍好一些:
但我甚至看不到頂行或垂直紅線水平紅線在第一列。我希望在那裏看到他們,但不被控制邊界覆蓋。如果你知道如何解決所有這些問題,請告訴我。
要知道,WPF使用矢量圖形,其中座標是不是像素,但浮點「設備無關的單位」(類型爲' double')。因此,在位置'(x,y)'處填充一個像素需要在'(x + 0.5,y + 0.5)'處用'厚度'設置爲'1.0'的筆繪製零長度線, StartLineCap'和'EndLineCap'設置爲'Square'。 – Clemens
@Clemens,我知道WPF的這種性質。這在WPF教程中的[this one](https://www.wpftutorial.net/DrawOnPhysicalDevicePixels.html)等許多文章中有解釋(請參閱'對齊邊緣而不是中心點'部分)。你認爲這將適用於任何屏幕分辨率和系統比例因子嗎? – TecMan
當然,你只需要記住座標原點在哪裏。如果你在'y = 0'處繪製水平線(並且控制片段到達邊界),則只會看到該線的下半部分。 – Clemens