我有<Grid>
,其中包含一些纵向和横向<Line>
。我希望网格可以随窗口大小进行扩展,并保持其宽高比,因此它包含在<Viewbox Stretch="Uniform">
中。
但是,我还希望线条总是以1像素的宽度渲染,所以我使用:
Line line = new Line();
line.SetValue(RenderOptions.EdgeModeProperty, EdgeMode.Aliased);
// other line settings here...
这使得线条的初始外观变得理想,但是一旦开始调整窗口大小,拉伸/缩放就会开始,并且线条再次成为1和2像素厚度的混合。
有没有办法让线条总是1像素厚,还可以调整窗口/网格的大小?
更新 - 根据Clemens的建议使用路径几何
@Clemens - 感谢您突出显示线条和路径之间的渲染差异。当我尝试使用你的例子重新编写我的代码时,我会感觉到我正在为自己挖掘更多的漏洞,并没有真正掌握整个概念(完全是我的错,不是你的,我只是WPF的新手)
我将添加一些截图来说明以下说明:
我正在制作一个游戏板(用于Go游戏,以防万一有助于理解布局)。我有一个9x9网格,我打算通过简单地将椭圆添加到特定网格单元来放置游戏块。
然而,为了在板上绘制底层线条,我需要在板上绘制与单元格中间相交的线条(在Go中,片段放置在交叉点上,而不是单元格的中间位置。)
很可能我采取了完全错误的方法,请随时告诉我重新开始不同的路线,而不是在当前结构中进行黑客攻击。
这就是我到目前为止的方式(由于计算坐标的方式,我以编程方式添加路径。不确定是否可以在XAML中完成):
XAML:
<Grid MinHeight="400" MinWidth="400" ShowGridLines="False" x:Name="boardGrid">
<Grid.Resources>
<ScaleTransform x:Key="transform"
ScaleX="{Binding ActualWidth, ElementName=boardGrid}"
ScaleY="{Binding ActualHeight, ElementName=boardGrid}" />
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<!-- more rows, 9 in total -->
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<!-- more columns, 9 in total -->
</Grid.ColumnDefinitions>
<!-- example game pieces -->
<Ellipse Stroke="Black" Fill="#333333" Grid.Row="3" Grid.Column="2" />
<Ellipse Stroke="#777777" Fill="#FFFFFF" Grid.Row="4" Grid.Column="4" />
</Grid>
C#:
int cols = 9;
int rows = 9;
// Draw horizontal lines
for (int row = 0; row < rows; row++)
{
var path = new System.Windows.Shapes.Path();
path.Stroke = Brushes.Black;
path.StrokeThickness = 1;
path.SetValue(RenderOptions.EdgeModeProperty, EdgeMode.Aliased);
Grid.SetRow(path, row);
Grid.SetColumnSpan(path, cols);
Grid.SetZIndex(path, -1);
double cellWidth = boardGrid.ColumnDefinitions[0].ActualWidth;
double cellHeight = boardGrid.RowDefinitions[0].ActualHeight;
double x1 = (cellWidth / 2) / boardGrid.ActualWidth;
double y1 = (cellHeight / 2) / boardGrid.ActualHeight;
double x2 = ((cellWidth * cols) - (cellWidth / 2)) / boardGrid.ActualWidth;
double y2 = (cellHeight / 2) / boardGrid.ActualHeight;
path.Data = new LineGeometry(new Point(x1, y1),
new Point(x2, y2),
(ScaleTransform)boardGrid.TryFindResource("transform"));
boardGrid.Children.Add(path);
}
// Similar loop code follows for vertical lines...
这是我在使用上面的代码时得到的
这就是我想要的样子。它为我提出了两个问题:
1)我是否采用正确的方法计算x1
,x2
,y1
和y2
值,方法是将它们按总板宽度计算到创建一个介于0和1之间的数字,以便然后可以将ScaleTransform应用于它们吗?
2)现在我不再使用Viewbox
了,如何实现固定比例缩放?如果我放大窗户,电路板会不成比例地伸展(见下图)。 (它不再对行进行反别名,这很好。)
我知道这将成为一个单一的帖子。我非常感谢你的耐心和回应。
答案 0 :(得分:10)
Viewbox只能“直观地”缩放其子元素,包括任何渲染笔划的粗细。你需要的是一个仅适用于线条(或其他形状)几何形状的缩放,但不会影响笔划。
您可以通过Path
对象使用已转换的LineGeometries作为Data
属性,而不是使用Line
个对象。您可以创建一个ScaleTransform
,它使用网格的宽度和高度作为x和y方向的缩放因子,从逻辑坐标缩放到视口坐标。每个LineGeometry(或任何其他几何)将使用0..1:
<Grid x:Name="grid">
<Grid.Resources>
<ScaleTransform x:Key="transform"
ScaleX="{Binding ActualWidth, ElementName=grid}"
ScaleY="{Binding ActualHeight, ElementName=grid}"/>
</Grid.Resources>
<Path Stroke="Black" StrokeThickness="1">
<Path.Data>
<LineGeometry StartPoint="0.1,0.1" EndPoint="0.9,0.9"
Transform="{StaticResource transform}"/>
</Path.Data>
</Path>
</Grid>
为了获得统一缩放,您可以简单地将ScaleTransform的ScaleX
和ScaleY
属性绑定到网格的ActualWidth
或ActualHeight
:
<Grid x:Name="grid">
<Grid.Resources>
<ScaleTransform x:Key="transform"
ScaleX="{Binding ActualWidth, ElementName=grid}"
ScaleY="{Binding ActualWidth, ElementName=grid}"/>
</Grid.Resources>
...
</Grid>
你也可以从宽度和高度的最小值计算出均匀比例因子,后面还有一些代码:
<Grid x:Name="grid" SizeChanged="grid_SizeChanged">
<Grid.Resources>
<ScaleTransform x:Key="transform"/>
</Grid.Resources>
...
</Grid>
使用像这样的SizeChanged处理程序:
private void grid_SizeChanged(object sender, SizeChangedEventArgs e)
{
var transform = grid.Resources["transform"] as ScaleTransform;
var minScale = Math.Min(grid.ActualWidth, grid.ActualHeight);
transform.ScaleX = minScale;
transform.ScaleY = minScale;
}