Reputation: 13441
I have a classic master-detail logic and trying to create instance of detail UIViewController with InstantiateViewController inside a click event.
Here is my code,
MasterViewController.cs
detailButton += delegate {
UIStoryboard Storyboard = UIStoryboard.FromName ("Main", null);
Console.WriteLine("InstantiateViewController() started");
var profileController = Storyboard.InstantiateViewController("ProfileController") as ProfileController;
Console.WriteLine("InstantiateViewController() ended");
profileController.Id = 5;
};
ProfileViewController.cs
public partial class ProfileController : UIViewController
{
public int Id { get; set; }
public override void ViewDidLoad()
{
Console.WriteLine("ViewDidLoad() called");
}
}
When I click the button output is,
InstantiateViewController() started
ViewDidLoad() called
InstantiateViewController() ended
This means profileController.Id
is set after ViewDidLoad()
which means I can't load data by Id in ViewDidload event beacuse Id is null.
So my question is why ViewDidLoad()
called by InstantiateViewController(), in which method should I load data by Id?
Thanks.
Upvotes: 2
Views: 674
Reputation: 74174
I would do this via a custom segue.
1) Create a custom segue that can be re-used throughout your app:
public class CustomSeque : UIStoryboardSegue // or UIStoryboardPopoverSegue depending upon UI design so you can "POP" controller
{
public CustomSeque(String identifier, UIViewController source, UIViewController destination) : base (identifier, source, destination) { }
public override void Perform()
{
if (Identifier == "StackOverflow")
{
// Are you using a NavigationController?
if (SourceViewController.NavigationController != null)
SourceViewController.NavigationController?.PushViewController(DestinationViewController, animated: true);
else
SourceViewController.ShowViewController(DestinationViewController, this);
} else
base.Perform();
}
}
2) Then you can:
UIStoryboard Storyboard = UIStoryboard.FromName("Main", null);
Console.WriteLine("InstantiateViewController() started");
var profileController = Storyboard.InstantiateViewController("ProfileController") as ProfileController;
var seque = new CustomSeque($"StackOverflow", this, profileController);
profileController.Id = 5;
profileController.PrepareForSegue(seque, this); // instead of *this*, you can pass any NSObject that contains data for your controller
seque.Perform();
Console.WriteLine("InstantiateViewController() ended");
If your ProfileController
looks like this:
public partial class ProfileController : UIViewController
{
public ProfileController (IntPtr handle) : base (handle)
{
Id = -99;
}
public int Id { get; set; }
public override bool ShouldPerformSegue(string segueIdentifier, NSObject sender)
{
if (segueIdentifier == "StackOverflow")
return true;
return base.ShouldPerformSegue(segueIdentifier, sender);
}
[Export("prepareForSegue:sender:")]
public override void PrepareForSegue(UIStoryboardSegue segue, NSObject sender)
{
base.PrepareForSegue(segue, sender);
Console.WriteLine("ProfileController.PrepareForSegue()");
Console.WriteLine($" - ID = {Id}");
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
Console.WriteLine("ProfileController.ViewDidLoad()");
Console.WriteLine($" - ID = {Id}");
}
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
Console.WriteLine("ProfileController.ViewWillAppear()");
Console.WriteLine($" - ID = {Id}");
}
}
Your sequenced output would be:
InstantiateViewController() started
ProfileController.PrepareForSegue()
- ID = 5
ProfileController.ViewDidLoad()
- ID = 5
InstantiateViewController() ended
ProfileController.ViewWillAppear()
- ID = 5
Upvotes: 1
Reputation: 7850
VoewDidLoad
is called when the ViewController
is loaded into memory.
So, the correct place to get the data is on ViewDidAppear
.
ViewDidAppear
notifies the ViewController
that its view was added to a view hierarchy.
UPDATE:
Based on the new information provided in comments you could do something like this:
public partial class ProfileController : UIViewController
{
private int _id;
public void SetupProfile (int id)
{
// Save the Id if necessary.
_id = id;
// Add event with this id related.
}
public override void ViewDidLoad()
{
Console.WriteLine("ViewDidLoad() called");
}
}
In alternative if you still want to do the event setup in ViewDidAppear
you could use this approach with the events:
yourClass.Event -= MyHandler;
yourClass.Event += MyHandler;
Upvotes: 1