2009-01-21 97 views
3

當我嘗試在WPF中使用抗鋸齒圖形時,出現奇怪的渲染問題。WPF中的抗鋸齒工件

這裏是一個簡化版本。

如果我用下面的XAML

<Window x:Class="RenderingBug.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Width="300" Height="300"> 
    <Grid Name="myGrid" Background="AntiqueWhite" Width="250" Height="250"> 
     <ScrollViewer Name="myScrollViewer" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"> 
      <Canvas Height="500" Width="500" Name="myCanvas" /> 
     </ScrollViewer>   
    </Grid> 
</Window> 

而下面的CS

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Data; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Imaging; 
using System.Windows.Navigation; 
using System.Windows.Shapes; 

namespace RenderingBug 
{ 
    /// <summary> 
    /// Interaction logic for Window1.xaml 
    /// </summary> 
    public partial class Window1 : Window 
    { 
     public Window1() 
     { 
      InitializeComponent(); 

      PathFigureCollection pfc = new PathFigureCollection(); 
      PathFigure pf = new PathFigure(); 
      pf.StartPoint = new Point(100, 20); 
      LineSegment ls = new LineSegment(); 
      ls.Point = new Point(20, 100); 
      PathSegmentCollection psc = new PathSegmentCollection(); 
      psc.Add(ls); 
      pf.Segments = psc; 
      pfc.Add(pf); 
      PathGeometry pg = new PathGeometry(pfc); 

      RectangleGeometry clippingRectangle = new RectangleGeometry(new Rect(0, 0, 80, 80)); 

      Path p1 = new Path(); 
      p1.ClipToBounds = true; 
      p1.Clip = clippingRectangle; 
      p1.StrokeDashCap = PenLineCap.Square; 
      p1.Stroke = Brushes.Black; 
      p1.StrokeThickness = 30; 
      p1.Data = pg; 
      myCanvas.Children.Add(p1); 

      Path p2 = new Path(); 
      p2.ClipToBounds = true; 
      p2.Clip = clippingRectangle; 
      p2.StrokeDashCap = PenLineCap.Square; 
      p2.Stroke = Brushes.White; 
      p2.StrokeThickness = 10; 
      p2.Data = pg; 
      myCanvas.Children.Add(p2); 
     } 
    } 
} 

我得到一個奇怪的渲染問題,與在裁剪矩形邊緣(運行程序抗鋸齒,這將是相當明顯的,但它是一個朦朧的灰色線,其中裁剪矩形截斷路徑)。

我已經嘗試了各種技術,如調整控制ols到特定的像素,並在各種控制上設置SnapsToDevicePixels,希望這可以解決這個問題(去除額外的模糊灰色帶),但似乎沒有任何幫助。

任何想法?

回答

3

原來,這是因爲雖然窗口當然是在像素邊界上對齊,但窗口內的網格可能不是。解決這個問題並不是太困難,但需要一段時間才能確定要做什麼。

有一個很好的功能稱爲SnapsToDevicePixels,應該可以正確對齊所有內容。而且,不幸的是,無論出於何種原因,它似乎都不起作用(這似乎是一個理解錯誤)。那麼該怎麼辦?

首先,網格必須在像素邊界對齊(即不居中或類似的東西),因爲如果窗口在水平或垂直方向上具有奇數個像素,則網格以及因此網格內容,將會出現錯位。)

但是接下來還有其他問題需要處理......只要開始滾動滾動條,工件就會重新出現!這是因爲滾動條不一定會滾動內容整數個像素。爲了解決這個問題,我在ScrollViewer中捕獲了一些事件來將滾動位置設置爲整數值。

private void workingAreaScrollViewer_SizeChanged(object sender, SizeChangedEventArgs e) 
{ 
    double w = e.NewSize.Width; 
    double h = e.NewSize.Height; 
    workingAreaScrollViewer.Width = Math.Round(w); 
    workingAreaScrollViewer.Height = Math.Round(h); 
} 

private void Window_KeyDown(object sender, KeyEventArgs e) 
{ 
    if (e.Key == Key.A) 
    { 
     workingAreaCanvas.Children.Remove(p2); 
    } 
    if (e.Key == Key.Z && p2.Parent != workingAreaCanvas) 
    { 
     workingAreaCanvas.Children.Add(p2); 
    } 
} 

這樣做,一切似乎都很好。 (請注意,對於ScrollViews中存在圖像問題的人...如果您遇到同樣的問題,這也應該解決這個問題,只要圖像不縮放,旋轉等等......只要你只是想把圖像對準像素邊界,這應該可以完成這項工作。)