2009-08-19 4 views
2

J'applique actuellement une classe appelée SelectionBorder dans WPF. C'est dérivé de la classe Shape.Création de SelectionBorder: Bit dans le visage par arrondi décimal?

Il ressemble fondamentalement ceci:

public class SelectionBorder : Shape 
{ 
    public Point StartPoint {get; set;} 
    public PointCollection Points {get; set;} 

    public double StrokeLength {get; set;} 

    protected override Geometry DefiningGeometry{ 
     get{ 
      //Magic! 
     } 
    } 

} 

Le StartPoint et les points propriétés déterminent les coins de la frontière. La bordure est une bordure de trait typique (un trait noir, un trait invisible comme celui-ci: - - - -)

Le problème que j'ai maintenant est que puisque les points d'angle sont librement choisis, il est assez commun que le nombre de les traits (signifiant des traits noirs et invisibles) ne sont pas pairs (en fait, ils ne sont même pas des nombres entiers) et, par conséquent, le premier trait semble plus long que les autres (visible sur l'image). Cela peut ne pas sembler être un gros problème mais je veux plus tard animer la bordure de sorte que les traits entourent le contenu. Lorsque vous faites cette animation, la petite faille dans la vue statique devient clairement visible et, à mon avis, est très dérangeante.

alt text http://img14.imageshack.us/img14/2874/selectionborder.png

Le problème est que j'ai essayé de déterminer une longueur de course qui obtient aussi près du original que possible longueur de course et crée un nombre pair de coups. Cependant le problème que j'ai rencontré est que WPF (évidemment) ne peut pas afficher toute la précision d'un StrokeLength double décimal et donc le nombre de traits qui en résulte est encore une fois inégal.

Y a-t-il une solution de contournement pour ce problème? Avez-vous probablement une autre solution pour mon problème?

Merci d'avance!

EDIT: J'ai testé et revu le code après une petite pause pour la forme physique aujourd'hui et après tout, il arrive seulement sur de très gros StrokeLengths. Je prévois d'utiliser StrokeLengths de 2 où le petit saut d'animation importe beaucoup moins que ce que je pensais à l'origine.

Répondre

0

Je viens de trouver un moyen qui rend la création d'un tel SelectionBorder animé. Au lieu de créer l'animation en déplaçant un AnimationPoint créé par l'animation, j'ai simplement animé la propriété StrokeDashOffset fournie nativement par la classe Shape et en définissant StrokeDashArray pour définir StrokeLength.

Il ressemblerait à ceci en XAML:

<namespace:SelectionBorder StrokeDashArray="2" AnimationDuration="0:0:1" Stroke="Black" /> 

La classe ressemble à ceci:

public class SelectionBorder : Shape 
{ 
    private DoubleAnimation m_Animation; 
    private bool m_AnimationStarted; 

    public SelectionBorder() 
    { 
     IsVisibleChanged += OnIsVisibleChanged; 
    } 

    protected void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) 
    { 
     if (Visibility == Visibility.Visible) 
     { 
      StartAnimation(); 
     } 
     else 
     { 
      StopAnimation(); 
     } 
    } 

    public void StartAnimation() 
    { 
     if (m_AnimationStarted) 
      return; 

     if (m_Animation == null) 
     { 
      m_Animation = CreateAnimation(); 
     } 

     BeginAnimation(StrokeDashOffsetProperty, m_Animation); 
     m_AnimationStarted = true; 
    } 

    protected virtual DoubleAnimation CreateAnimation() 
    { 
     DoubleAnimation animation = new DoubleAnimation(); 
     animation.From = 0; 
     if (StrokeDashArray.Count == 0) 
      animation.To = 4; 
     else 
      animation.To = StrokeDashArray.First() * 2; 
     animation.Duration = AnimationDuration; 
     animation.RepeatBehavior = RepeatBehavior.Forever; 
     return animation; 
    } 

    public void StopAnimation() 
    { 
     if (m_AnimationStarted) 
     { 
      BeginAnimation(StrokeDashOffsetProperty, null); 
      m_AnimationStarted = false; 
     } 
    } 

    #region Dependency Properties 

    public Duration AnimationDuration 
    { 
     get { return (Duration)GetValue(AnimationDurationProperty); } 
     set { SetValue(AnimationDurationProperty, value); } 
    } 

    public static readonly DependencyProperty AnimationDurationProperty = 
     DependencyProperty.Register("AnimationDuration", typeof(Duration), typeof(SelectionBorder), new UIPropertyMetadata(new Duration(TimeSpan.FromSeconds(0.5)))); 


    #endregion Dependency Properties 

    protected override Geometry DefiningGeometry 
    { 
     get 
     { 
      double width = (double.IsNaN(Width)) ? ((Panel)Parent).ActualWidth : Width; 
      double height = (double.IsNaN(Height)) ? ((Panel)Parent).ActualHeight : Height; 

      RectangleGeometry geometry = new RectangleGeometry(new Rect(0, 0, width, height)); 

      return geometry; 
     } 
    } 
} 
1

Vous pouvez rendre plusieurs coins "non-appariés" à cet égard. Par exemple, au lieu d'avoir un point comme "source" et "destination" des tirets animés, vous pouvez choisir 2 points. L'un serait la «source», les tirets semblant s'en éloigner dans deux directions, et un autre point serait la «destination», où les tirets convergent et disparaissent. Par exemple, GIMP anime les lignes pointillées de sélection de cette manière et semble choisir un point le plus proche du coin inférieur gauche pour la "source" et un point le plus proche du coin supérieur droit pour la "destination".

Vous pourriez également trouver un autre schéma. N'oubliez pas que même si cela peut vous déranger, la plupart des utilisateurs ne s'en soucieront pas.

+0

Vous où j'avais raison peut-être un peu à pointilleux. Le conseil avec 2 points de départ est également très bon. Merci! – chrischu