使用自定义渲染器强制重绘Xamarin.Forms视图

我有一个可视化元素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); } } } } 

按下button时,红色边界应变成蓝色。 显然,渲染器不会注意到已更改的属性。 我如何触发重绘?

(这个例子是针对iOS的,但是我的问题也适用于Android。)

Solutions Collecting From Web of "使用自定义渲染器强制重绘Xamarin.Forms视图"

首先,把你的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 (); } 

需要两个修改:

  1. BoundaryColor属性的setter中调用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