0

I have a controller called LeftViewController representing a sidemenu for my main controller ViewController. I want when I click a button in the sidemenu to call a function in the main ViewController and change the title of my button. I tried to define a class refresh_all in ViewController.cs to be responsible of updating titles of my button , and from there I would define an object from ViewController to call a function from it.

 public  class refresh_all{


        ViewController v1 = new ViewController();

        public void refresh_components()
        {


            v1.refresh_ac(); //

        }

    }

Function in ViewController class :

 public void refresh_ac()
        {
            s2.SetTitle(CommonClass.value.ToString(), UIControlState.Normal);//s2 is my button name
        }

I defined an object from refresh_all class in LeftViewController controller as follow :

    partial void Conbtn_TouchUpInside(UIButton sender)
        {

            refresh_all r1 = new refresh_all();

            r1.refresh_components();

        }

I am getting an error on s2.SetTitle(CommonClass.value.ToString(), UIControlState.Normal); saying Object reference not set to an instance of an object

Help is much appreciated.

2 Answers2

1

Can you please check s2 button object and CommonClass object. "CommonClass.value" Here CommonClass should be an instance/object of the class to call the properties.

Send the ViewController object in LeftViewController and then send to the refresh_all class.

Jai Gupta
  • 1,374
  • 9
  • 8
0

Events

I managed to get the event approch working. My information was based on the following links:

In my UITableViewController (view controller B) I added the following:

// class variable  
public event EventHandler<BLevelSelectedEventArgs> BLevelSelected;

// event handler
public class BLevelSelectedEventArgs : EventArgs
{
    public BLevelItem bLevel { get; set; }

    public BLevelSelectedEventArgs(BLevelItem bLevel) : base()
    { 
        this.bLevel = bLevel;
    }
}

Here the event as well as the custom event handler is defined. You can define the properties you want to transport the data with the event e.g. string. Here a custom BLevelItem is used. The name of the event handler and the name of the event should be changed for your application. In this UITableViewController class I also have the UITableViewSource defined.

public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
    tableView.DeselectRow (indexPath, true); // iOS convention is to remove the highlight

    if (this.controller.BLevelSelected != null) {
        this.controller.BLevelSelected (this, new BLevelSelectedEventArgs (controller.bLevelList[indexPath.Row]));
    }

}

Here the event is raised and the parameter are passed with the event. Now only one listener is missing which reacts on the event. This goes on view controller A:

bLevelController.BLevelSelected += (object sender, BLevelController.BLevelSelectedEventArgs e) => {
    System.Diagnostics.Debug.WriteLine(e.bLevel.bLevelName);
};

bLevelController is an instance of my view controller B. You can access the defined event as seen above, but you have to be aware that you use the class name (BLevelController) to access BLevelSelectedEventArgs.

It would be nice if one you could also add the other possibilities to pass the data between view controllers (Notification center, Protocol/Delegates, ...).


Delegate

A kind of delegate method is used Part 5 - Working with Tables in the iOS Designer. You define a Delegate in your UITableViewController:

public MasterViewController Delegate {get;set;} // will be used to Save, Delete later

When you instantiate the DetailViewController in the MasterViewController you set the Delegate property. Example:

public override void PrepareForSegue (UIStoryboardSegue segue, NSObject sender)
{
    base.PrepareForSegue (segue, sender);

    var detailViewController = segue.DestinationViewController as DetailViewController;

    if (detailViewController != null) {
        detailViewController.Delegate = this;
    }
}

In the DetailViewController you can call any method from the MasterViewController:

public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
    {
    tableView.DeselectRow (indexPath, true); // iOS convention is to remove the highlight
    if (this.controller.Delegate != null) {
        this.controller.Delegate.SetItems (this.controller.items[indexPath.Row]);
    }
}

// a method in MasterViewController
public void SetItems(string items){
    this.items = items;
    this.NavigationController.PopViewControllerAnimated (true);
    // do something here
}

This works because I pass the DetailViewController to the DetailViewSource:

// in ViewDidLoad of DetailViewController
this.TableView.Source = new DetailViewSource (this);

// in the constructor of DetailViewSource
private CostCentreController controller;

public CostCentreListSource (CostCentreController controller)
{
    this.controller = controller;
}

NSNotificationCenter

My information are based on xamarin/monotouch-samples and Xamarin NSNotificatioCenter: How can I get the NSObject being passed?.

Simple example without data transfer:

// class level variable
NSObject observer;

// register as observer
public override void ViewWillAppear (bool animated)
{
    base.ViewWillAppear (animated);
    observer = NSNotificationCenter.DefaultCenter.AddObserver ((NSString)UIDevice.OrientationDidChangeNotification, OrientationChanged);
}

// deregister as observer
public override void ViewDidDisappear (bool animated)
{
    base.ViewDidDisappear (animated);
    if (observer != null) { 
        NSNotificationCenter.DefaultCenter.RemoveObserver (observer);
        observer = null;
    }
}

// function which should do something when notification is received
public void OrientationChanged(NSNotification notification){
    Console.WriteLine ("test");
    // perhaps you can do the following as in the linked SO question: NSObject myObject = notification.Object;
}

Referenc here

Leo Zhu
  • 15,726
  • 1
  • 7
  • 23