Custom renderer OnDraw not being called when invalidated?

CRoscoeCRoscoe CAMember ✭✭
edited July 2015 in Xamarin.Forms

I am trying to make essentially a canvas equivalent since Xamarin.Forms does not natively have one.

For the Android renderer I can get it to the point where OnElementPropertyChanged gets called, and in it it does call "this.Invalidate();" to force OnDraw, but my OnDraw never gets called.

Any ideas? Is there a better way to force Android to redraw/call OnDraw?

Answers

  • CRoscoeCRoscoe CAMember ✭✭

    RefreshDrawableState() does not seem to fire off OnDraw either.

  • adamkempadamkemp USInsider, Developer Group Leader mod

    Custom renderers in Android are ViewGroups, and by default those do not call OnDraw because they usually don't do their own drawing. To override this you need to call SetWillNotDraw(false) (yes, this is a stupid name) at some point, probably in the constructor.

  • CRoscoeCRoscoe CAMember ✭✭

    I already have this.SetWillNotDraw(false); in the constructor of the renderer.

  • adamkempadamkemp USInsider, Developer Group Leader mod

    Could you attach an example project showing what you're trying to do?

  • CRoscoeCRoscoe CAMember ✭✭

    I thought I pasted my code here, however it does not appear to be here... It probably needed to be validated or something.

    Anyway, I attached the files of the project below. It limited me to sending 50mb if I sent the whole file (since Xamarin's base files are huge for some reason), so I just cleaned it up to isolate it.

  • CRoscoeCRoscoe CAMember ✭✭

    I forgot a file there. This one has the missing file (essentially loading the canvas objects Content)

  • CRoscoeCRoscoe CAMember ✭✭

    The renderer looks like this:

    public class RectRenderer : VisualElementRenderer {
    private DrawRect drawSender;

      public RectRenderer() {
          this.SetWillNotDraw(false);
      }
    
      protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) {
          base.OnElementPropertyChanged(sender, e);
    
          if (e.PropertyName == DrawRect.WidthProperty.PropertyName) //Tried with multiple of DrawRect properties.
                  this.Invalidate(); // Force a call to OnDraw
    
          drawSender = ((DrawRect)sender);
      }
    
      protected override void OnDraw(Canvas canvas) {
          base.OnDraw (canvas);
          var element = this.Element;
          var rect = new Rect();
          this.GetDrawingRect(rect);
          var paint = new Paint() {
              Color = element.Color.ToAndroid(),
              AntiAlias = true,
              StrokeWidth = drawSender.StrokeWidth,
              Alpha = drawSender.Opacity
          };
    
          if (!drawSender.Fill)
              paint.SetStyle(Paint.Style.Stroke);
    
          canvas.DrawRect(new RectF(rect), paint);
      }
    

    }

    and my object it is bound to is this:

    public class DrawRect : DrawElement {
    public static readonly BindableProperty ColorProperty =
    BindableProperty.Create<DrawRect, Color>(p => p.Color, Color.Accent);

      public Color Color {
          get { return (Color)GetValue(ColorProperty); }
          set { SetValue(ColorProperty, value); }
      }
    

    }

    public class DrawElement : View {
    private bool fill;
    private int strokeWidth;
    public bool Fill {get; set;}
    public int StrokeWidth {get; set;}
    }

  • CRoscoeCRoscoe CAMember ✭✭

    The renderer looks like this:

    public class RectRenderer : VisualElementRenderer {
    private DrawRect drawSender;

      public RectRenderer() {
          this.SetWillNotDraw(false);
      }
    
      protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) {
          base.OnElementPropertyChanged(sender, e);
    
          if (e.PropertyName == DrawRect.WidthProperty.PropertyName) //Tried with multiple of DrawRect properties.
                  this.Invalidate(); // Force a call to OnDraw
    
          drawSender = ((DrawRect)sender);
      }
    
      protected override void OnDraw(Canvas canvas) {
          base.OnDraw (canvas);
          var element = this.Element;
          var rect = new Rect();
          this.GetDrawingRect(rect);
          var paint = new Paint() {
              Color = element.Color.ToAndroid(),
              AntiAlias = true,
              StrokeWidth = drawSender.StrokeWidth,
              Alpha = drawSender.Opacity
          };
    
          if (!drawSender.Fill)
              paint.SetStyle(Paint.Style.Stroke);
    
          canvas.DrawRect(new RectF(rect), paint);
      }
    

    }

    and my object it is bound to is this:

    public class DrawRect : DrawElement {
    public static readonly BindableProperty ColorProperty =
    BindableProperty.Create<DrawRect, Color>(p => p.Color, Color.Accent);

      public Color Color {
          get { return (Color)GetValue(ColorProperty); }
          set { SetValue(ColorProperty, value); }
      }
    

    }

    public class DrawElement : View {
    private bool fill;
    private int strokeWidth;
    public bool Fill {get; set;}
    public int StrokeWidth {get; set;}
    }

  • adamkempadamkemp USInsider, Developer Group Leader mod

    I just had time to look at this. You haven't given me a working project. I don't have time to recreate a whole solution and project to inject this code. Just create a working sample project and zip up the whole solution directory.

  • MaxMengMaxMeng NZMember ✭✭✭
Sign In or Register to comment.