2009-01-21 7 views
3

J'ai un problème de rendu bizarre lorsque j'essaie d'utiliser des graphiques anti-aliasés dans WPF.Artefacts anti-aliasing dans WPF

Voici une version simplifiée.

Si j'utilise le XAML suivant

<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> 

Et le suivant 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); 
     } 
    } 
} 

je reçois un problème de rendu étrange avec l'anti-aliasing où le bord du rectangle de recadrage est (en cours d'exécution du programme, ce sera assez évident, mais c'est une ligne grise brumeuse où le rectangle de recadrage tronque les chemins.)

J'ai essayé diverses techniques comme l'alignement du contr ols à des pixels spécifiques, et en définissant SnapsToDevicePixels sur les différents contrôles dans l'espoir que cela résoudrait ce problème (supprimez le groupe gris supplémentaire flou), mais rien ne semble aider.

Des idées?

Répondre

3

Il s'avère que c'est parce que bien que la fenêtre est, bien sûr, alignée sur une limite de pixels, la grille dans la fenêtre peut ne pas être. Corriger cela n'est pas trop difficile, mais cela peut prendre un certain temps pour comprendre ce qu'il faut faire.

Il existe une fonctionnalité intéressante appelée SnapsToDevicePixels qui devrait aligner correctement tous les éléments. Et, malheureusement, pour une raison quelconque, cela ne semble pas fonctionner du tout (cela semble être un bug compris). Alors que faire? Tout d'abord, la grille doit être alignée à une limite de pixels (c'est-à-dire non centrée) ou quelque chose comme ça puisque si la fenêtre a un nombre impair de pixels dans la direction horizontale ou verticale, la grille , sera désaligné.)

Mais alors, il y a d'autres problèmes à traiter ... dès que vous commencez à faire défiler les barres de défilement, l'artefact réapparaît! C'est parce que les barres de défilement ne font pas nécessairement défiler le contenu d'un nombre entier de pixels. Pour faire face à cela, je capture certains événements dans le ScrollViewer pour définir l'emplacement de défilement à des valeurs entières.

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); 
    } 
} 

Faites-le, et tout semble bien se passer. (En note, pour les personnes qui ont des problèmes d'image à l'intérieur de ScrollViews ... si vous rencontrez le même problème, cela devrait également corriger cela, tant que l'image n'est pas mise à l'échelle, pivotée , etc ... tant que vous essayez juste d'aligner l'image à une limite de pixels, cela devrait faire l'affaire.)