Создание SelectionBorder:Укусить в лицо десятичным округлением?

StackOverflow https://stackoverflow.com/questions/1299706

  •  18-09-2019
  •  | 
  •  

Вопрос

В настоящее время я реализую класс SelectionBorder в WPF.Он является производным от класса Shape.

В основном это выглядит так:

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

}

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

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

альтернативный текст http://img14.imageshack.us/img14/2874/selectionborder.png

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

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

Заранее спасибо!

РЕДАКТИРОВАТЬ:Сегодня я повторно протестировал и пересмотрел код после небольшого перерыва на фитнес, и ведь это происходит только на очень больших StrokeLengths.Я планирую использовать StrokeLengths, равный 2, где небольшие прыжки анимации имеют гораздо меньшее значение, чем я изначально думал.

Это было полезно?

Решение 2

Я только что нашел способ, который упрощает создание такого анимированного 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;
        }
    }
}

Другие советы

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

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

Можно придумать и другую схему.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top