I write a control that derived a class from the FrameworkElement and overrode its OnRender method. Inside this method, there is a DrawLine animation by providing an AnimationClock instance to drawingContext.DrawLine method.
It works well if there are only a few lines, and it doesn't work any more if there are hundreds of lines. AffectsRender and InvalideVisual() method also doesn't work, it can't call the OnRender method. If there are a middling number of lines, it doesn't work, but if I resize the window, it works! And I found that if I change the DependencyProperty (which has the AffectsRender flag) and add a new visual at the same time, it works no matter how many lines are in the window.
I have looked up some articles that said that WPF is a retained graphics and the OnRender method is invoked by WPF itself. It is WPF that determine when the OnRender need to be invoked. How can I do to tell WPF to invoke OnRender?
Here are the codes:
class PipeLine:FrameworkElement
{
static PipeLine()
{
SignalInputProperty = DependencyProperty.Register("SignalInput", typeof(int), typeof(PipeLine),
new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.AffectsRender));
SignalOutputProperty = DependencyProperty.Register("SignalOutput", typeof(bool), typeof(PipeLine),
new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender));
}
public static readonly DependencyProperty SignalInputProperty;
public int SignalInput
{
get { return (int)GetValue(SignalInputProperty); }
set
{
SetValue(SignalInputProperty, value);
}
}
public static readonly DependencyProperty SignalOutputProperty;
public bool SignalOutput
{
get { return (bool)GetValue(SignalOutputProperty); }
set { SetValue(SignalOutputProperty, value); }
}
protected override void OnRender(System.Windows.Media.DrawingContext drawingContext)
{
base.OnRender(drawingContext);
Point startPH = new Point(0, ActualHeight / 2);
Point endPH = new Point(ActualWidth, ActualHeight / 2);
Point startPH1 = new Point(-this.ActualHeight / 2, this.ActualHeight / 2);
Point endPH1 = new Point(this.ActualWidth + this.ActualHeight / 2, this.ActualHeight / 2);
PointAnimation animation = new PointAnimation();
animation.From = startPH;
animation.To = endPH;
animation.Duration = new Duration(TimeSpan.FromSeconds(2.0));
AnimationClock clock = animation.CreateClock();
Pen pen1 = new Pen(Brushes.DarkGray, ActualHeight);
Pen pen2 = new Pen(Brushes.LightSkyBlue, ActualHeight);
if (SignalInput == 2 && !SignalOutput)
{
drawingContext.DrawLine(pen1, startPH, endPH);
drawingContext.DrawLine(pen2, startPH, null, endPH, clock);
}
else
{
drawingContext.DrawLine(pen1, startPH, endPH);
SignalOutput = false;
}
}
void clock_Completed(object sender, EventArgs e)
{
this.SignalOutput = true;
}
}