Finally figured out how delegate = self works in Xamarin.iOS

Published by Brad on

Quite often when using Xamarin.iOS (MonoTouch) you will find yourself having to port objective-c samples to C#. One thing that has always bothered me is when I find a line like this.
myTextView.delegate = self;
The solution I always go for is
myTextView.Delegate = this;
But this will cause a "Cannot implicitly convert type" compiler error. Take a look at this simple ViewController example.
public class ViewController : UIViewController
{
    public ViewController()
    {

    }

    public override void ViewDidLoad()
    {
        base.ViewDidLoad();

        UITextView myTextView = new UITextView(new RectangleF(10, 30, 300, 50));
        myTextView.Text = "bradmoore.com.au";
        View.AddSubview(myTextView);
    }
}
If I wanted to, lets say, fire a method everytime the text is changed I would normally do this.
public class MyTextViewDelegate : UITextViewDelegate
{
    ViewController _controller = null;

    public MyTextViewDelegate(ViewController controller)
    {
        _controller = controller;
    }

    public override void Changed(UITextView textView)
    {
        _controller.MyTextVeiwChanged();
    }
}

public class ViewController : UIViewController
{
    public ViewController()
    {

    }

    public override void ViewDidLoad()
    {
        base.ViewDidLoad();

        UITextView myTextView = new UITextView(new RectangleF(10, 30, 300, 50));
        myTextView.Delegate = new MyTextViewDelegate(this);
        myTextView.Text = "bradmoore.com.au";
        View.AddSubview(myTextView);
    }

    public void MyTextVeiwChanged()
    {
        // DO STUFF
    }
}
Which works great in my opinion and does what I need it to do BUT there is a better way! Rather than using myTextView.Delegate, I can actually use myTextView.WeakDelegate and set it to this. Thanks goes to Clancey on #monotouch (irc.gimp.org) IRC channel for pointing this out for me. To make the method fire I simply need to export its selector like so.
class ViewController : UIViewController
{
    public ViewController()
    {

    }

    public override void ViewDidLoad()
    {
        base.ViewDidLoad();

        UITextView myTextView = new UITextView(new RectangleF(10, 30, 300, 50));
        //myTextView.Delegate = new MyTextViewDelegate(this);
        myTextView.WeakDelegate = this;
        myTextView.Text = "bradmoore.com.au";
        View.AddSubview(myTextView);
    }

    [Export("textViewDidChange:")]
    public void MyTextVeiwChanged()
    {
        // DO STUFF
    }
}
The key part is the "textViewDidChange:" which is the same as how the normal objective-c method name would be written. If you want to find out what other selectors to use for certain events you can just simply write UITextViewDelegate somewhere in your source code, right mouse click on it and select "Go to Declaration". This will then open the assembly browser where you can see how all the other selectors are already exported. Assembly Browser

4 Comments

James Clancey · March 25, 2014 at 6:37 am

Even better, you can change class ViewController : UIViewController, ITextViewDelegate...

Now you can just type override and you will see TextViewDidChange, and it will add the selector for you when you choose it.

    bradm · March 25, 2014 at 9:48 am

    This is amazing. I am going to save so much time now! Three years doing MT programming and am still learning new tips everyday 🙂

Enmud · September 19, 2014 at 5:40 pm

HI I want to shouldchangecharsinrange uitextfield delegate method for a uitextfield in uialertviewstyleplainTextinput in Xamarin.
Can any body know how to implement the delegate method for the uitextfield.

Ricardo · May 11, 2016 at 2:50 am

You just saved my life! I knew that there should be a simple and clean solution like this one.
Thank you so much!

Leave a Reply

Your email address will not be published. Required fields are marked *