【问题标题】:Force redraw of Xamarin.Forms View with custom renderer使用自定义渲染器强制重绘 Xamarin.Forms 视图
【发布时间】:2014-09-27 09:13:36
【问题描述】:

我有一个视觉元素 MyButton,带有为 iOS 实现的自定义渲染器。

共享:

namespace RendererTest
{
    public class MyButton: Button
    {
        public Color BoundaryColor { get; set; }
    }

    public static class App
    {
        public static Page GetMainPage()
        {    
            var button = new MyButton { Text = "Click me!", BoundaryColor = Color.Red };
            button.Clicked += (sender, e) => (sender as MyButton).BoundaryColor = Color.Blue;
            return new ContentPage { Content = button };
        }
    }
}

iOS:

[assembly:ExportRenderer(typeof(MyButton), typeof(MyButtonRenderer))]

namespace RendererTest.iOS
{
    public class MyButtonRenderer: ButtonRenderer
    {
        public override void Draw(RectangleF rect)
        {
            using (var context = UIGraphics.GetCurrentContext()) {
                context.SetFillColor(Element.BackgroundColor.ToCGColor());
                context.SetStrokeColor((Element as MyButton).BoundaryColor.ToCGColor());
                context.SetLineWidth(10);
                context.AddPath(CGPath.FromRect(Bounds));
                context.DrawPath(CGPathDrawingMode.FillStroke);
            }
        }
    }
}

按下按钮时,红色边界应变为蓝色。显然渲染器没有注意到更改的属性。如何触发重绘?

(此示例适用于 iOS。但我的问题也适用于 Android。)

【问题讨论】:

    标签: android ios xamarin xamarin.forms custom-renderer


    【解决方案1】:

    首先,将您的BoundaryColor 变成一个可绑定的属性。这不是必需的,触发INPC 事件就足够了,但是你可以绑定到它:

    public static readonly BindableProperty BoundaryColorProperty =
        BindableProperty.Create ("BoundaryColor", typeof(Color), typeof(MyButton), Color.Default);
    
    public Color BoundaryColor {
        get { return (Color)GetValue (BoudaryColorProperty); }
        set { SetValue (BoundaryColorProperty, value); }
    }
    

    然后,在您的渲染器中:

    protected override void OnElementPropertyChanged (object sender, PropertyChangedEventArgs e)
    {
        base.OnElementPropertyChanged (sender, e);
    
        if (e.PropertyName == MyButton.BoundaryColorProperty.PropertyName)
            SetNeedsDisplay ();
    }
    

    【讨论】:

    • 我在设置BoundaryColor 时尝试触发public event Action BoundaryColorChanged。在MyButtonRenderer 构造函数中,我将订阅该事件并调用SetNeedsDisplay()。但是,如果这样做,我会收到 System.Reflection.TargetInvocationException
    • 如果我不在渲染器的构造函数中订阅,但在 Draw 方法内订阅,它可以工作。但这可能不是最好的解决方案,因为我会继续为事件添加 (+=) 侦听器。
    • 您不必附加到 PropertyChanged 事件,OnElementChanged 已经为您附加,您只需覆盖它。
    • @StephaneDelcroix 什么相当于 SetNeedsDisplay ();在安卓?因为我也需要在 Android 上做。
    【解决方案2】:

    需要进行两次修改:

    1. BoundaryColor 属性的设置器中调用OnPropertyChanged

      public class MyButton: Button
      {
          Color boundaryColor = Color.Red;
      
          public Color BoundaryColor {
              get {
                  return boundaryColor;
              }
              set {
                  boundaryColor = value;
                  OnPropertyChanged();  // <-- here
              }
          }
      }
      
    2. 订阅MyButtonRendererOnElementChanged方法内的事件:

      public class MyButtonRenderer: ButtonRenderer
      {
          protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
          {
              base.OnElementChanged(e);
              Element.PropertyChanged += (s_, e_) => SetNeedsDisplay();  // <-- here
          }
      
          public override void Draw(RectangleF rect)
          {
              // ...
          }
      }
      

    注意:OnElementChanged 中订阅似乎很重要,而不是在构造函数中。否则会引发 System.Reflection.TargetInvocationException

    【讨论】:

    • SetNeedsDisplay() 在 Android 上调用的等效项是什么?
    • @kaolick:那就是Invalidate()
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-29
    • 2016-05-31
    • 2017-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多