I have a visual element MyButton
with a custom renderer implemented for iOS.
Shared:
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);
}
}
}
}
When pressing the button, the red boundary should become blue. Apparently the renderer does not notice the changed property. How can I trigger a redraw?
(This example is for iOS. But my question applies to Android as well.)
First, turn you BoundaryColor
into a bindable property. That's not required, firing INPC
event is enough, but then you can bind to it:
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); }
}
then, in your renderer:
protected override void OnElementPropertyChanged (object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged (sender, e);
if (e.PropertyName == MyButton.BoundaryColorProperty.PropertyName)
SetNeedsDisplay ();
}
Two modifications were required:
Call
OnPropertyChanged
within the setter of theBoundaryColor
property:public class MyButton: Button { Color boundaryColor = Color.Red; public Color BoundaryColor { get { return boundaryColor; } set { boundaryColor = value; OnPropertyChanged(); // <-- here } } }
Subscribe to the event within the
OnElementChanged
method ofMyButtonRenderer
: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) { // ... } }
Note:
It seems to be important to subscribe within OnElementChanged
and not the constructor. Otherwise a System.Reflection.TargetInvocationException
is raised.
来源:https://stackoverflow.com/questions/25126433/force-redraw-of-xamarin-forms-view-with-custom-renderer