Here's what it does in my Home View:
So when I select European slice, it's normal only one ToolTip pops up when the Pointer
(Vertical Line) is over the Circle
, for the first time it's always normal no matter which slice I select. When I select African slice, now I get two ToolTip for each point and when I select Asian slice, I get three! I'm not sure what the issue is BUT I guess it's because of the static event, Moved
, in my Pointer
class. Here is Pointer
:
public class Pointer : UIElement
{
Pen pen;
Point start, end;
public static event Action<double> Moved;
public Pointer() {
pen = new Pen(Brushes.Blue, 1) { DashStyle = DashStyles.DashDotDot, DashCap = PenLineCap.Round };
start = new Point();
end = new Point();
}
public void SetPointer(double x1, double y2, double labelWidth) {
start.X = end.X = x1;
start.Y = labelWidth;
end.Y = y2;
InvalidateVisual();
Moved(x1);
}
protected override void OnRender(DrawingContext drawingContext) => drawingContext.DrawLine(pen, start, end);
}
and it's that static event. Circle
class is the subscriber, here's the Circle
:
public class Circle : FrameworkElement
{
public object value;
int radius;
Path path;
EllipseGeometry circle;
RadialGradientBrush radialBrush;
GradientStop firstStop;
DoubleAnimation gradStopAnim;
DoubleAnimation scaleAnim;
double leftBound, rightBound;
HomeLineTip tip;
public Circle(object value) {
this.value = value;
tip = new HomeLineTip(value);
radius = 8;
firstStop = new GradientStop(Colors.LightBlue, 0);
radialBrush = new RadialGradientBrush() {
GradientOrigin = new Point(0.5, 0.5),
GradientStops = {
firstStop,
new GradientStop(Color.FromArgb(100, 255, 0, 0), 1)
}
};
circle = new EllipseGeometry() { RadiusX = radius, RadiusY = radius };
path = new Path() {
Fill = radialBrush,
Data = circle
};
gradStopAnim = new DoubleAnimation() {
BeginTime = TimeSpan.FromSeconds(0.5),
Duration = TimeSpan.FromSeconds(1),
EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseInOut }
};
scaleAnim = new DoubleAnimation() {
Duration = TimeSpan.FromSeconds(1),
EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseInOut }
};
RenderTransform = new ScaleTransform();
Loaded += appear;
Pointer.Moved += DetectLine;
}
void appear(object sender, RoutedEventArgs e) {
var anim = new DoubleAnimation() {
BeginTime = TimeSpan.FromSeconds(2),
Duration = TimeSpan.FromSeconds(1),
To = 0.5,
EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseInOut }
};
RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, anim);
RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, anim);
}
void animate() {
firstStop.BeginAnimation(GradientStop.OffsetProperty, gradStopAnim);
RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, scaleAnim);
RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, scaleAnim);
}
void DetectLine(double x) {
if (x != 0) {
if (x >= leftBound && x <= rightBound) {
if (gradStopAnim.To != 1) {
gradStopAnim.To = scaleAnim.To = 1;
animate();
tip.IsOpen = true;
}
}
else {
if (gradStopAnim.To == 1) {
gradStopAnim.To = 0.25;
scaleAnim.To = 0.5;
animate();
tip.IsOpen = false;
}
}
}
}
public void SetCenter(Point center) {
circle.Center = center;
leftBound = center.X - radius;
rightBound = center.X + radius;
var transform = RenderTransform as ScaleTransform;
transform.ScaleX = transform.ScaleY = 0;
transform.CenterX = center.X;
transform.CenterY = center.Y;
InvalidateVisual();
}
protected override void OnRender(DrawingContext drawingContext) => drawingContext.DrawGeometry(radialBrush, null, path.Data);
}
In the last line of Construction I've Pointer.Moved += DetectLine;
. When I select a slice ItemSourceProperty
of my LineChart
class changes and in it's PropertyChangeCallback, onSourceChanged
, I do this:
static void onSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
var o = d as LineChart;
o.labelDesired = new Size(0, 0);
if (e.OldValue != null) {
o.Children.Clear();
}
o.Children.Add(new Border() { Background = Brushes.Transparent });
var values = ((IEnumerable)e.NewValue).Cast<DepositDueRent>().ToList();
var path = new LineStream(values.Select(x => x.Amount).ToList());
o.Children.Add(path);
o.maxValue = 0;
foreach (var value in values) {
o.Children.Add(new Circle(value));
o.addLabel(MainVM.spaces.First(x => x.Id == value.SpaceId).Name);
if (value.Amount > o.maxValue) o.maxValue = value.Amount;
if (value.Amount < o.minValue) o.minValue = value.Amount;
}
var min = o.minValue < 0 ? o.minValue : 0;
double step = 0d;
var current = min;
step = min < 0 ? ((o.maxValue) + Math.Abs(min)) / 9 : (o.maxValue) / 9;
for (int i = 0; i < 10; i++) {
o.addLine();
o.addTick(current);
current += step;
}
o.numPoints = values.Count;
o.Children.Add(new Pointer());
o.InvalidateArrange();
}
I clear all its children with o.Children.Clear();
BUT I don't know how to unsubscribe from static event so I didn't. How to remove all handler from that static Moved
event when the ItemSource changes?