8

<Grid>はいくつかの垂直と水平<Line>のを含むを持っています。グリッドをウィンドウサイズに合わせてスケーラブルにし、アスペクト比を維持したいので、グリッドはに含まれてい<Viewbox Stretch="Uniform">ます。

ただし、線を常に1ピクセルの幅でレンダリングしたいので、次を使用します。

Line line = new Line();
line.SetValue(RenderOptions.EdgeModeProperty, EdgeMode.Aliased);
// other line settings here...

これにより、線の最初の外観が理想的になりますが、ウィンドウのサイズ変更を開始するとすぐに、ストレッチ/スケーリングが開始され、線は再び1ピクセルと2ピクセルの太さの混合になります。

線を常に1ピクセルの太さにし、ウィンドウ/グリッドのサイズを変更できるようにする方法はありますか?

更新-クレメンスの提案に従ってパスジオメトリを使用する

@Clemens-ラインとパスのレンダリングの違いを強調していただきありがとうございます。あなたの例を使用してコードを作り直そうとすると、自分自身のためにもっと穴を掘っていて、概念全体を実際に把握していないという沈没感を覚えています(完全に私のせいであり、あなたのせいではなく、私はWPFに慣れていないだけです) 。

次の説明を説明するために、スクリーンショットをいくつか追加します。

私はゲームボードを作っています(囲碁のゲームの場合、レイアウトを理解するのに役立ちます)。私は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...

これは、上記のコードを使用したときに得られるものです

パスを使用した場合の結果

これは私がそれをどのように見せたいかとほぼ同じです。それは私のためにさらに2つの質問を提起しました:

1)、、、、および値をボードの合計幅でダイビングして0から1までの数値を作成し、ScaleTransformを適用できるようにするという正しいアプローチを取っていますx1か?x2y1y2

2)使用しViewboxなくなったので、固定比率のスケーリングを実行するにはどうすればよいですか?ウィンドウを拡大すると、ボードのバランスが崩れます(下の画像を参照)。(ただし、ラインをアンチエイリアス処理することはもうありません。これはすばらしいことです。)

伸ばされたボードはアスペクト比を失います

私はこれが少しモノリシックな投稿になりつつあることを知っています。何卒ご理解とご協力を賜りますようお願い申し上げます。

4

1 に答える 1

11

Viewbox は、レンダリングされたストロークの太さを含め、その子要素を「視覚的に」スケーリングすることしかできません。必要なのは、線 (または他の形状) のジオメトリにのみ適用され、ストロークは影響を受けないスケーリングです。

オブジェクトを使用する代わりに、プロパティに変換されたLineGeometryLineを使用するオブジェクトによって線を描画できます。グリッドの幅と高さを x 方向と y 方向の倍率として使用して、論理座標からビューポート座標にスケーリングする を作成できます。各 LineGeometry (またはその他のジオメトリ) は、範囲 0..1 の論理座標を使用します。PathDataScaleTransform

<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 のScaleXScaleYプロパティの両方を Gridの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;
}
于 2013-03-10T14:19:26.820 に答える