Creazione SelectionBorder: Bit in faccia da arrotondamento decimale?
Domanda
Al momento sto implementando una classe chiamata SelectionBorder in WPF. E 'derivato dalla classe Shape.
Si presenta sostanzialmente in questo modo:
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!
}
}
}
il punto di inizio e punti di proprietà determinano gli angoli del confine. Il confine è un tipico bordo linea accarezzato (un tratto nero, un colpo invisibile così: - - - -)
Il problema che ho ora è che, poiché i punti d'angolo sono liberamente choosable è abbastanza comune che il conteggio dei colpi (ovvero tratti neri e invisibili) non è nemmeno (in realtà nemmeno un numero intero) e quindi il primo aspetto ictus più lungo degli altri (visibile nella foto). Questo forse non sembra essere un grosso problema, ma poi voglio animare il confine in modo che i colpi cerchio intorno al contenuto. Nel fare questa animazione il piccolo difetto nella visione statica diventa chiaramente visibile e, a mio parere è molto preoccupante.
alt text http://img14.imageshack.us/img14/2874/selectionborder .png
Il problema è che ho cercato di stabilire uno StrokeLength che ottiene più vicino possibile al StrokeLength originale possibile e crea un numero di colpi. Tuttavia il problema che ho incontrato è che WPF (ovviamente) non è in grado di visualizzare l'intera precisione di uno StrokeLength doppia decimale e quindi il numero di corse risultante non è uniforme, ancora una volta.
C'è una soluzione per questo problema? Cosa probabilmente si dispone di un'altra soluzione per il mio problema?
Grazie in anticipo!
EDIT: ho riprovato e rivisto il codice dopo una piccola pausa per il fitness oggi e dopo tutto succede solo su molto grande StrokeLengths. Ho intenzione di utilizzare StrokeLengths del 2 dove la piccola animazione salto importa molto meno di quanto inizialmente pensato.
Soluzione 2
ho appena trovato un modo che rende modo più semplice per creare un tale SelectionBorder animato.
Invece di creare l'animazione muovendo un AnimationPoint auto-creato attraverso l'animazione Ho appena animato la proprietà StrokeDashOffset nativamente fornito dalla classe Shape e l'impostazione del StrokeDashArray per definire la StrokeLength.
Si sarebbe simile a questa in XAML:
<namespace:SelectionBorder StrokeDashArray="2" AnimationDuration="0:0:1" Stroke="Black" />
La classe si presenta così:
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;
}
}
}
Altri suggerimenti
Si potrebbe fare più di un angolo "un-abbinato" al riguardo. Ad esempio, invece di avere un punto sia la "sorgente" e "destinazione" dei trattini animati, si poteva scegliere 2 punti. Uno potrebbe essere la "fonte", trattini apparendo a marciare a partire da esso in 2 direzioni, e un altro punto la "destinazione", dove convergono i trattini e scompaiono.
GIMP, per esempio, anima selezione linee tratteggiate in questo modo e sembra selezionare un punto più vicino alla parte inferiore sinistra per la "sorgente" e un punto più vicino alla parte superiore destra per la "destinazione".
Si potrebbe trovare un qualche altro schema, pure.
Basta ricordare che, mentre può sembrare inquietante a te, maggior parte degli utenti non si cura.