0

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;
    }
}
RambleInX
  • 143
  • 11

2 Answers2

0

In WPF OnRender method is called when Arrange or Measure occurs. So I guess this is the answer to second part of your question.

VidasV
  • 4,335
  • 1
  • 28
  • 50
0

The problem is that SignalOutput value does not change . It gets True on the first tick . And then it gets true again and again .

A dependency property isn't updated if OldValue == NewValue.

So the DP does not affect the Render because it was not effected itself.

void clock_Completed(object sender, EventArgs e)
{
    this.InvalidateVisual();
}
eran otzap
  • 12,293
  • 20
  • 84
  • 139
  • Thanks.The InputSignal property is changed manually by a serious logicals, if the InputSignal is 2 then it will draw a line use an animation. If the animation is completed, it will gave the SignalOutput property a true value. But if the InputSignal is other value, it will draw a line without an animation and set the SignalOuput property a false value. – RambleInX Jan 21 '15 at 02:10
  • @RambleInX could it be that SignalOutput was true and you set it again to true , or is it always true false true false ... ? – eran otzap Jan 21 '15 at 07:26
  • the value of SignalOutput is determined by SignalInput. the value of SignalInput is determined by myself. that's to say, the SignalOutput is determined by myself, it can be true, true, false...true, false, true...etc – RambleInX Jan 22 '15 at 00:12
  • Again , If it was True and you set it again to True the value did not change and OnRender was not called. if it was true and then false and then true only then will OnRender – eran otzap Jan 22 '15 at 07:34