I carry a uitableview with a collection of objects.
And when I click on a UITableViewCell open another UIView.
But I wanted to send the object that is in UITableViewCell for this new UIView and there to show their details.
I followed to answer this question to load another view: ViewController Segue Xamarin
I am very grateful if someone help
There are a few solutions, first one is to use
prepareForSegue(_:sender:) method:
Discussion
The default implementation of this method does nothing; you
can override it to pass relevant data to the new view controller or
window controller, based on the context of the segue. The segue object
describes the transition and includes references to both controllers
involved in the segue.
Segues can be triggered from multiple sources, so use the information
in the segue and sender parameters to disambiguate between different
logical paths in your app. For example, if the segue originated from a
table view, the sender parameter would identify the cell that the user
clicked. You could use that information to set the data on the
destination view controller.
In thi case you need to "save" an object that you want to pass in didSelectRow:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
self.currentObjectToPass = .. some object from array or somewhere else..
}
And then set it to next vc:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(UIButton*)sender {
if ([segue.identifier isEqualToString:#"bookingDetailsSegue"]) {
self.nextVC = segue.destinationViewController;
self.nextVC.objectToPass = self.currentObjectToPass;
}
}
The other way is to refuse of using of segues and get vc by its storyboardID.
This way you need
instantiateViewController(withIdentifier:) method:
Return Value The view controller corresponding to the specified
identifier string. If no view controller is associated with the
string, this method throws an exception.
Discussion You use this method to create view controller objects that
you want to manipulate and present programmatically in your
application. Before you can use this method to retrieve a view
controller, you must explicitly tag it with an appropriate identifier
string in Interface Builder.
This method creates a new instance of the specified view controller
each time you call it.
Then your code will look like this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
self.nextVC = [self.storyboard instantiateViewControllerWithIdentifier:#"nextVCID"];
self.nextVC.objectToPass = = .. some object from array or somewhere else..
[self.navigationController pushViewController:self.nextVC animated:YES];
}
And don't forget to set vc identifier (Storyboard ID) in IB here:
override PrepareForSegue in your ViewController to set parameters on the destination controller. You will need to define public methods or properties on the destination controller that allow you to pass parameters:
public override void PrepareForSegue (UIStoryboardSegue segue, NSObject sender)
{
if (segue.Identifier == "TaskSegue") { // set in Storyboard
var navctlr = segue.DestinationViewController as TaskDetailViewController;
if (navctlr != null) {
// some public method you create in your destination controller
navctlr.SetTask (this, item);
}
}
}
Related
I have a Xamarin.iOS application which includes a Navigation Controller where the root in a View Controller ViewController.cs, inside the UIViewController (the default one created in a single view application) is a Table View which has a segue to a new View Controller.
Depicted in Storyboard below.
The Table view is controlled by the StationsTableViewSource.cs code which inherits from UITableViewSource. The source for the Table View is set inside the ViewController.cs.
StationsTable.Source = new StationsTableViewSource(StationPlayer.StationsTitleList)
When I press a cell in the table view I want to segue to the new view controller but as I see it:
I have no access to the Parent/Root/Containing View Controller from the Table View
I have no access to the New View Controller from the Table View.
My question is this, with a set up as above, how can I perform a segue from a cell inside a tableview nested in a View Controller to another View Controller?
Please correct the terminology - not too hot on Xamarin/iOS lingo.
Thanks all.
First of all, we need to figure out which segue have you created?
1.From your tableViewCell to a new ViewController.
This means: tap down on the Cell + ctrl and drag to a new ViewContoller. In this way, there's no need to execute PerformSegue() manually. When you click the Cell, it will push to a new Controller.
2.From your ViewContoller to a new ViewController
This means: tap down on the bottom bar of the ViewContoller + ctrl and drag to a new ViewController. In this way, we need to click the segue we created above then set the Identifier. When we click the Cell, the event below will be triggered:
public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
//use this method we can push to a new viewController
//the first parameter is the identifier we set above
parentVC.PerformSegue("NewPush", indexPath);
}
I have no access to the Parent/Root/Containing View Controller from
the Table View
When you construct this Source you can pass your "Parent" ViewController like:
ViewController parentVC;
//You can add other parameters you want in this initial method
public MyTableViewCellSource(ViewController viewController, ...)
{
parentVC = viewController;
}
Moreover both segues will fire PrepareForSegue() in the parent ViewController. In this method you can pass parameters to the new ViewController:
public override void PrepareForSegue(UIStoryboardSegue segue, NSObject sender)
{
if (segue.Identifier == "NewPush")
{
SecondVC secondVC = segue.DestinationViewController as SecondVC;
...//do some configuration
}
}
About how to use segue, you can read this official documentation for more details.
I am new to Xamarin development and I am trying to build simple IOS app.
I have a situation with 2 ViewControllers with specific classes ( FirstViewController, SecondViewController) and segue set between them.
When I try to pass data from the first one to the second in this code, everything is ok :
public override void PrepareForSegue(UIStoryboardSegue segue, NSObject sender)
{
base.PrepareForSegue(segue, sender);
var viewController = (SecondViewController)segue.DestinationViewController;
viewController.Number = 1;
}
But when I set an identifier to segue, I get a NullReferenceException. There is no SecondViewController in DestinationViewController, but UIViewController.
What is even weirder is that when i remove the identifier, the exception is still there. Any Ideas ?
The problem was that when you change the namespace of a ViewController it gets detached from the Storyboard View.
I set up a segue with a navigation controller in Xamarin.iOS. The first screen is just a ViewController that has a List of phoneNumbers, and adds to the list of phone numbers when a button is clicked. When a different button is clicked, I want to go to the CallHistory2 screen and display the list of phone numbers. However, I'm having trouble passing the List object to the second screen.
This is a method in the ViewController.cs class (the first screen)
public override void PrepareForSegue (UIStoryboardSegue segue, NSObject sender)
{
base.PrepareForSegue (segue, sender);
// set the View Controller that’s powering the screen we’re
// transitioning to
var callHistoryContoller = segue.DestinationViewController as CallHistory2;
//set the Table View Controller’s list of phone numbers to the
// list of dialed phone numbers
if (callHistoryContoller != null) {
callHistoryContoller.PhoneNumbers = PhoneNumbers;
}
}
I get an error at this line
var callHistoryContoller = segue.DestinationViewController as CallHistory2;
Cannot convert type 'UIKit.UIViewController' to 'PortableAppTest.iOS.CallHistory2' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion PortableAppTest.iOS
When I change CallHistory2 to UITableViewController the error goes away, but then callHistoryController won't contain a reference to my CallHistory2 class (implements UITableViewController), but rather to a generic UITableViewController class.
How do I work around this issue? Any help is appreciated!
try following, It will work .
if ( segue.DestinationViewController.GetType() == typeof(CallHistory2))
{
CallHistory2 callHistoryContoller = (CallHistory2)segue.DestinationViewController
callHistoryContoller.PhoneNumbers = PhoneNumbers;
}
I hope this helps someone else as I ran into the same issue!
This is from Xamarins Multiscreen guide
https://developer.xamarin.com/guides/ios/getting_started/hello,_iOS_multiscreen/hello,_iOS_multiscreen_quickstart/
And the issue for me was that the app is called "PhoneWord" but the code for this Viewcontroller was using "Phoneword" as the namespace (notice the lower case W)
As soon as I set it correctly it worked as expected.
I have custom controls: CustomControlOne, CustomControlTwo.
My CustomControlOne has a List<CustomControlTwo> showed in your properties panel of my windows form application project:
So when I click in the button, a window to add new items in this collection is opened:
But, I want add existing CustomControlTwo items that are defined in MyForm. ps.: MyForm contains CustomControlOne and multiple CustomControlTwo.
I want this items can be added in design time, like same way that selecting an item in a comboBox (in CustomControlOne properties panel). When I change List<CustomControlTwo> to ICollection<CustomControlTwo> a comboBox is showed but the items of type CustomControlTwo not appears :(
How I can do this ?
How I can say to my CustomControlOne where are the CustomControlTwo items ?
Thx.
UPDATE:
I wrote my own UITypeEditor and I reached my goal with help of #Sefe and with THIS link. Bellow my code:
public class CollectionTypeEditor : UITypeEditor {
private IWindowsFormsEditorService _editorService = null;
private ICollection<Control> mControls = null;
private List<Control> mPickedControls = null;
// Editor like Modal style
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) {
return UITypeEditorEditStyle.Modal;
}
// Opens modal and get returned data
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) {
if (provider == null)
return value;
_editorService = (IWindowsFormsEditorService) provider
.GetService(typeof(IWindowsFormsEditorService));
if (_editorService == null)
return value;
mControls = new List<Control>();
// retrieve old data
mPickedControls = value as List<Control>;
if (mPickedControls == null)
mPickedControls = new List<Control>();
// getting existent controls that will be inflated in modal
Control mContext = (Control) context.Instance;
GetControls(mContext);
// open form and get response
CollectionDesign<Control> frmCollections = new CollectionDesign<Control>(mControls, ref mPickedControls);
var response = _editorService.ShowDialog(frmCollections);
// returning data from editor
return response == DialogResult.OK ? mPickedControls : value;
}
Everything works well here. Now, my variable in properties panel:
[Editor(typeof(CollectionTypeEditor), typeof(UITypeEditor))]
[TypeConverter(typeof(ActionButtonConverter))]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public List<Control> ActionButtons { get; set; }
The serialization attribute was added because the file couldn't be saved. When form is closed and reopened, all data are lost.
The stranger thing is that I wrote other UITypeEditor like the same way, just changing type of data to string and I can close or reopen my form and all works fine, the data are saved.
I already added a TypeConverter but I think that isn't case here. what is wrong with my code?
My basic setup:
In this setup, BaseForm extends Form. With string works, but with List data are lost on close form or build project...
Resumed workflow:
1 - Open MyForm.
2 - Click at ActionButtons ellipsis [...] (inherited by BaseForm) on MyForm properties panel.
3 - A custom form is opened with inflated objects that I want pick.
4 - Objects that I want are picked and I close form. So now, data is ok cause I can reopen that form and see objects that I picked.
5 - Now when close the MyForm and reopen it, all data are lost. The same thing happens when build the project. But if I do all this steps with a string, all are Ok (data are saved).
Thanks all, and sorry for bad language :P
If you want to add multiple CustomControlTwo items to your control, a drop down list will do you no good, since you can only select one value there.
If you are able to change the property to accept a single instance of CustomControlTwo (or are OK that the list you can create in your property browser has only one item), you can create a new System.ComponentModel.TypeConverter that will create the list to select from. A type converter is an abstract class and you will have to implement a couple of abstract methods. The methods that are valuable to you are GetStandardValuesSupported, GetStandardValuesExclusive and GetStandardValues. Here is the part that is interesting to you (you have to add the other methods):
public class CustomControlOneConverter : TypeConverter {
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
{
//By returning true, you tell the property designer to add a drop down list
return true;
}
public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
{
//By returning true, you tell the property designer to not allow the user to enter his own text
return true;
}
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
//Get all objects of type CustomControlTwo from the container
CustomControlTwo[] controlsToList =
context.Container.Components.OfType<CustomControlTwo>().ToArray;
//Return a collection of the controls
return new StandardValuesCollection(controlsToList);
}
//implement the other abstract methods
}
What you do in GetStandardValues is to search in the container of CustomControlOne, if there are instances of CustomControlTwo. Those are then added to the list of standard values to select from in the property browser.
If you are not able to change your property to select only one CustomControlTwo, you will need to create your own UI to display when the ellipsis (...) is clicked in your property window. For that you need to create your own UITypeEditor. That, however is a more complex undertaking and is not easily explained in a nutshell.
I want to transfer all data from HomeAddressUC to PermanentAddressUC with checkBox SameAsPrevious
Each UserControl has same Type(AddressUserControl)
DataSource to Fill HomeAddressUC is code is like this
private void SetTabPageDetails(string tabPageName, CustomerDetails customerDetailsCache)
{
customerDetailsCache = // calling stored procedure
PermanentAddressUC.SetDetails(customerDetailsCache.Addresses[0]);
}
Scope of that DataSource is upto it method SetTabPageDetails() only
logic I was trying to implement is on checkbox changed event is
if (chkSameAsPervious.Checked)
{
foreach (var addressCtl in from Control ctl in this.ADDRESS_TAB.Controls select ctl as BankSys24.UI.UserControls.AddressUserControl)
{
if (addressCtl.GroupBoxText == "Mailing Address")
{
// want to do something here
}
}
}
I try to follow the relevant link
Best practice when you need two user controls (winforms) to communicate
it says to use the Third Common User Control a Container or interface
What is the optimized way to do it?
Why you need to different user controls for home and mailing address if all the fields same?
you can use one user control for both and create property for set the group name as "Home address" or "Mailing address"
You can have two public methods to set address fields by passing address object and get address object by reading fields of the form.
On check change event of the checkbox you can get address object by calling home address user control instant get address method and then you can set that details on mailing address user control instant by calling set address method by passing address object.
Possible Shortest Solution I Found is like this :
if (chkSameAsPervious.Checked)
{
MailingAddressUC.SetDetails(PermanentAddressUC.GetDetails() as BankSys24.DTO.Customer.Address);
}
where
public object GetDetails()
{
return new BankSys24.DTO.Customer.Address { //data };
}
and
public void SetDetails(object input)
{
//intermediate Object
if (details != null)
{
//Mapping
}
Getdetails maps the all data as Container Class Object which can be Directly pass to SetDetails() ...