调用方法并将数据从视图控制器 B 传递到 Xamarin.iOS 中的视图控制器 A

问题描述:

我有一个视图控制器 A,我可以在其中检索一些值.在某些情况下,如果有多个可用值,用户必须选择一个值.所以我展示了另一个视图控制器 B (UITableView),让用户选择条目.当我目前在 B 上时,如何从 A 调用方法?(避免重复代码)我如何在该方法中传递一些参数?

I have a view controller A where I retrieve some values. Under certain circumstances the user has to select a value if multiple are available. So I present another view controller B (UITableView) where I let the user select the entry. How can I call a method from A when I'm currently on B? (to avoid duplicate code) And how can I pass some params in that method?

我了解了 delegates/protocols事件(.NET 样式) 和通知*.传递字符串并从 A 调用方法的最佳方法是什么?你能举个例子吗?在 Xamarin 的示例中,没有关于如何定义自定义协议的示例.

I read about delegates/protocols, events (.NET style), and notification center. What is the best way to pass a string and call the method from A? Could you provide an example? In the example from Xamarin there is no example of how to define a custom protocol.

或者我应该从 A 公开一个字段并将这个字段传递给我处理数据的视图控制器 B?

Or should I make a field from A public and pass this field to view controller B where I work with the data?

事件

我设法使事件接近工作.我的信息基于以下链接:

Events

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

在我的 UITableViewController(视图控制器 B)中,我添加了以下内容:

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;
    }
}

此处定义了事件以及自定义事件处理程序.您可以定义要与事件一起传输数据的属性,例如细绳.这里使用了自定义 BLevelItem.应该为您的应用程序更改事件处理程序的名称和事件的名称.在这个 UITableViewController 类中,我还定义了 UITableViewSource.

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]));
    }

}

此处引发事件,参数随事件一起传递.现在只缺少一个对事件做出反应的侦听器.这在视图控制器 A 上进行:

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 是我的视图控制器 B 的一个实例.你可以像上面看到的那样访问定义的事件,但你必须注意你使用的类名(BLevelController) 访问 BLevelSelectedEventArgs.

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, ...).

使用了一种委托方法 第 5 部分 - 使用iOS 设计器中的表格.您在 UITableViewController 中定义了一个 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

当您在 MasterViewController 中实例化 DetailViewController 时,您设置了 Delegate 属性.示例:

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;
    }
}

DetailViewController 中,您可以从 MasterViewController 调用任何方法:

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
}

这是可行的,因为我将 DetailViewController 传递给了 DetailViewSource:

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

我的信息基于 xamarin/monotouch-samplesXamarin NSNotificatioCenter:我怎样才能获得正在传递 NSObject?.

没有数据传输的简单示例:

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;
}