Making a SelectionBorder: Bit to Face with Decimal Rounding?

I am currently implementing a class called SelectionBorder in WPF. It is derived from the Shape class.

It basically looks like this:

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

}

      

The StartPoint and Points properties define the corners of the border. Border - typical dashed line border (one back door, one invisible move: - - - -)

The problem I am running into now is that since the corner points are freely selectable, it is quite common that the stroke count (which means black and invisible strokes) is not even (actually not even an integer), and so the first stroke looks like longer than the rest (seen in the picture). This may not seem like a big deal, but later on I want to animate the border so that strokes surround the content. When doing this animation, a tiny flaw in the static view becomes apparent and, in my opinion, very disturbing.

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

The problem is that I tried to define a StrokeLength that is as close to the original StrokeLength as possible and produces an even number of strokes. However, the problem I am facing is that WPF (obviously) cannot display the full double decimal precision of StrokeLength and so the resulting stroke number is once again jagged.

Is there a workaround for the problem? Perhaps you have another solution for my problem?

Thanks in advance!

EDIT: I checked and looked at the code after a little fitness break today and in the end it only happens on very large StrokeLengths. I am planning on using StrokeLengths of 2, where the little animation jump matters a lot less than I originally thought.

+2


source to share


2 answers


I just found a way that makes it easier to create such an animated SelectionBorder.

Instead of creating an animation by moving a self-occupied AnimationPoint through the animation, I simply animated the StrokeDashOffset property originally provided by the Shape class and set the StrokeDashArray to define the StrokeLength.

In XAML it would look like this:



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

      

The class looks like this:

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

      

0


source


In this regard, you can make several "inconsistent" angles. For example, instead of one point being the "source" and "destination" of an animated dash, you could choose 2 points. One would be the "source", the silences appearing to move away from it in two directions, and the other point would be the "destination" where the dashes converge and disappear.

The GIMP, for example, animates the highlighted dotted lines in this way and appears to pick the point closest to the lower left for the "source" and the point closest to the upper right for the "destination".



You can also find another circuit.

Just remember that while you may find it frustrating, most users will not like it.

+1


source







All Articles