2009-08-19 1 views
2

В настоящее время я реализую класс под названием SelectionBorder в WPF. Он получен из класса Shape.Создание SelectionBorder: бит в лице десятичным округлением?

Это в основном выглядит следующим образом:

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

} 

начальный и Пункты свойства определяют углы границы. Граница - типичная штриховая граница линии (один черный ход, один невидимый такт: - - - -)

Проблема, которая возникает у меня сейчас, заключается в том, что, поскольку угловые точки свободно выбираются, довольно часто считается, что количество штрихи (что означает черные и невидимые штрихи) даже не (на самом деле даже не целое), и поэтому первый штрих выглядит длиннее остальных (видимых на картинке). Возможно, это не похоже на большое дело, но позже я хочу анимировать границу, чтобы штрихи окружали контент. При выполнении этой анимации крошечный недостаток в статическом представлении становится ясно видимым и, на мой взгляд, очень тревожным.

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

Проблема заключается в том, что я пытался определить StrokeLength, который получает, как близко к оригиналу, насколько это возможно StrokeLength и создает четное число ходов. Однако проблема, с которой я столкнулся, заключается в том, что WPF (очевидно) не может отобразить всю точность двойной десятичной StrokeLength, и поэтому полученный номер хода еще раз неровный.

Есть ли обходной путь для решения этой проблемы? Возможно, у вас есть другое решение для моей проблемы?

Заранее благодарен!

EDIT: Я пересмотрел и рассмотрел код после небольшого перерыва для фитнеса сегодня, и в конце концов это происходит только на очень больших StrokeLengths. Я планирую использовать StrokeLengths of 2, где маленький анимационный прыжок имеет значение намного меньше, чем я думал изначально.

ответ

0

Я просто нашел способ, который облегчает создание такого анимированного SelectionBorder.

Вместо создания анимации, перемещая самогенерируемую анимацию AnimationPoint через анимацию, я просто анимировал свойство StrokeDashOffset, изначально предоставленное классом Shape, и установив StrokeDashArray для определения StrokeLength.

Это будет выглядеть в XAML:

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

Класс выглядит следующим образом:

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

В этом отношении вы можете сделать более чем один угол «несогласованный». Например, вместо того, чтобы одна точка была «источником» и «местом назначения» анимированных тире, вы могли бы выбрать 2 очка. Один из них был бы «источником», черты, появляющиеся, чтобы отойти от него в двух направлениях, а другой точкой будет «пункт назначения», где тире сходятся и исчезают.

GIMP, например, анимирует выделенные пунктирные линии таким образом и, кажется, выбирает точку, ближайшую к нижней левой стороне для «источника» и точку, ближайшую к верхнему правую для «пункта назначения».

Вы также можете найти другую схему.

Просто помните, что, хотя это может показаться вам неприятным, большинству пользователей все равно.

+0

Вы где прямо я, возможно, был немного, чтобы разборчивы. Совет с 2 отправными точками также очень хорош. Благодаря! – chrischu