IOS用に実装されたカスタムレンダラーを備えたビジュアル要素MyButton
があります。
共有:
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にも当てはまります。)
2つの変更が必要でした:
OnPropertyChanged
プロパティのセッター内でBoundaryColor
を呼び出します。
public class MyButton: Button
{
Color boundaryColor = Color.Red;
public Color BoundaryColor {
get {
return boundaryColor;
}
set {
boundaryColor = value;
OnPropertyChanged(); // <-- here
}
}
}
OnElementChanged
のMyButtonRenderer
メソッド内でイベントをサブスクライブします。
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
が発生します。
まず、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 ();
}