7

と のみで構成される非常に初歩的なテスト アプリケーションがWindowありCustomControlます。ウィンドウにはカスタム コントロールが含まれ、次の追加属性があります。

TextOptions.TextFormattingMode="Display"
SnapsToDevicePixels="True" 
UseLayoutRounding="True"
RenderOptions.EdgeMode="Aliased"

カスタム コントロールでは、コード ビハインド ファイルに次の 5 行が追加されています。

protected override void OnRender(DrawingContext drawingContext)
{
    var pen = new Pen(Brushes.Black, 1);
    drawingContext.DrawLine(pen, new Point(0, 0), new Point(ActualWidth, ActualHeight)); 
}

すべてがうまく機能します。左上から右下に向かって斜めに 1px の黒い線が引かれます。完全。確かにピクセル化されていますが、まさに私が必要としているものです。ただし、ウィンドウを最小化して再度復元すると、線が「ぼやけて」しまいます。これはOnRender、ウィンドウが復元された後にメソッドが再度呼び出されることなく発生します。では、ウィンドウが最小化された後、描画されたグラフィックスが根本的に変化するのはなぜですか (フォーカスを失うことは問題ではないようです)。ウィンドウのサイズを変更しただけですべてが正常に戻るのはなぜですか? また、この望ましくない動作に対処するにはどうすればよいですか? WindowState変更が少し過剰に見えるたびに、完全なサイズ変更/無効化を強制していませんか?

更新 1:

@Backlashが示唆したように、カスタムコントロールをキャンバス内に配置しました

<Canvas Name="CanvasControl" SizeChanged="FrameworkElement_OnSizeChanged">
  <wpfTest:CustomControl x:Name="ChildControl" />
</Canvas>

SizeChangedこのようにイベントを処理しました

private void FrameworkElement_OnSizeChanged(object sender, SizeChangedEventArgs e)
{
    ChildControl.Width = CanvasControl.ActualWidth;
    ChildControl.Height = CanvasControl.ActualHeight;
}

キャンバス内の要素は自動的にレイアウトされないためです。しかし、結果は変わりませんでした。

更新 2:

Width私の頭をよぎった 1 つのアイデアは、ウィンドウの状態の変更をリッスンし、ウィンドウのまたはHeightプロパティをわずかに変更して、ウィンドウとそのすべてのコントロールのサイズ変更を強制することでした。したがって、完全に再描画します。

protected override void OnStateChanged(EventArgs e)
{
        if (WindowState != WindowState.Minimized)
        {               
            Width += 1;
        }
}

これは状況によっては機能しますが (Windowたとえば、 が最大化されている場合はそうではありません)、一般的に言えば、これはいくつかの理由からあからさまに悪いアプローチです。サイズが変更されたときに(正しい)再描画が発生する原因を理解しようとしましたが、それはCoreFlags.AreTransformsClean.

更新 3:

WPF はスクリーン上に直線を直接描画することで無力に過負荷になっているように見えるため、最初にメモリ内ビットマップに描画してから、ビットマップを画面にペイントしてみました。そして、それは機能します。メソッドは次のとおりです。

protected override void OnRender(DrawingContext drawingContext)
{
    var rtb = new RenderTargetBitmap((int)ActualWidth, (int)ActualHeight, 96, 96, PixelFormats.Pbgra32);
    var line = new Line();
    RenderOptions.SetEdgeMode(line, EdgeMode.Aliased);

    line.Stroke = Brushes.Black;
    line.StrokeThickness = 1;
    line.X1 = 0;
    line.X2 = ActualWidth;
    line.Y1 = 0;
    line.Y2 = ActualHeight;
    line.Arrange(new Rect(new Size((int)ActualWidth, (int)ActualHeight)));
    rtb.Render(line);

    drawingContext.DrawImage(rtb, new Rect(0, 0, (int)ActualWidth, (int)ActualHeight));
}

「解決策」は控えめに言ってもハックです。これは本当に悪いことですが、WPF からこれまでに見た残りの部分と比較すると、これは正当なアプローチかもしれません。ただし、さらに回答を得るためにスレッドを開いたままにします。

4

1 に答える 1

1

使っているからだと思います

SnapsToDevicePixels="True" 

Microsoft msdnによると、ピクセルのスナッピングは常に正確であるとは限りません。

残念ながら、コンテナー オブジェクトのサイズを調整するだけでは、デバイスのピクセルの配置は保証されません。アプリケーションのレイアウト全体が、画像の配置に影響を与える可能性があります。ディスプレイの 1 インチあたりのドット数 (dpi) も、画像の位置合わせに影響します。上記の例では、ディスプレイが 96 ドット/インチ (dpi) に設定されている場合にのみ、画像の位置合わせが機能します。その他の設定では、表示設定に合わせてレイアウトを調整する必要があります。Windows Presentation Foundation (WPF) アプリケーションでは、可能な限り高頻度の画像を避ける必要があります。

そのフラグをfalseに変更して、それが何をするか見てみましょう

于 2013-12-10T14:57:25.023 に答える