UIViewController subclass (mimics UITableViewController) doesn't get released - c#

I have subclassed UIViewController, which mimics UITableViewController == HUDTableViewController. Then I subclass from this subclassed view controller (SomeViewController : HUDTableViewController).
If I simulate a memory warning, SomeViewController doesn't get released. Here is the code of HUDTableViewController:
using System;
using Foundation;
using UIKit;
namespace MyApp
{
public class HUDTableViewController : UIViewController, IUITableViewDataSource, IUITableViewDelegate, IDisposable, IUIScrollViewDelegate
{
private UIView parentView;
private UITableView tableView;
public UITableView TableView
{
get
{
return this.tableView;
}
set
{
this.tableView = value;
}
}
public HUDTableViewController() : base()
{
Initialize();
}
private void Initialize()
{
this.tableView = new UITableView();
this.tableView.TranslatesAutoresizingMaskIntoConstraints = false;
this.tableView.WeakDelegate = this;
this.tableView.WeakDataSource = this;
this.parentView = new UIView();
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
this.parentView.AddSubview(this.tableView);
View = this.parentView;
NSMutableDictionary viewsDictionary = new NSMutableDictionary();
viewsDictionary["parent"] = this.parentView;
viewsDictionary["tableView"] = this.tableView;
this.parentView.AddConstraints(NSLayoutConstraint.FromVisualFormat("H:|[tableView]|", (NSLayoutFormatOptions)0, null, viewsDictionary));
this.parentView.AddConstraints(NSLayoutConstraint.FromVisualFormat("V:|[tableView]|", (NSLayoutFormatOptions)0, null, viewsDictionary));
}
[Foundation.Export("numberOfSectionsInTableView:")]
public virtual System.nint NumberOfSections(UIKit.UITableView tableView)
{
return 1;
}
public virtual System.nint RowsInSection(UIKit.UITableView tableview, System.nint section)
{
throw new NotImplementedException();
}
public virtual UIKit.UITableViewCell GetCell(UIKit.UITableView tableView, Foundation.NSIndexPath indexPath)
{
throw new NotImplementedException();
}
[Export("tableView:estimatedHeightForRowAtIndexPath:")]
public virtual System.nfloat EstimatedHeight(UIKit.UITableView tableView, Foundation.NSIndexPath indexPath)
{
return UITableView.AutomaticDimension;
}
[Foundation.Export("tableView:didSelectRowAtIndexPath:")]
public virtual void RowSelected(UIKit.UITableView tableView, Foundation.NSIndexPath indexPath)
{
}
[Export("tableView:heightForRowAtIndexPath:")]
public virtual System.nfloat GetHeightForRow(UIKit.UITableView tableView, Foundation.NSIndexPath indexPath)
{
return 44.0f;
}
[Foundation.Export("tableView:heightForHeaderInSection:")]
public virtual System.nfloat GetHeightForHeader(UIKit.UITableView tableView, System.nint section)
{
return UITableView.AutomaticDimension;
}
[Foundation.Export("tableView:viewForHeaderInSection:")]
public virtual UIKit.UIView GetViewForHeader(UIKit.UITableView tableView, System.nint section)
{
return null;
}
[Export("tableView:titleForHeaderInSection:")]
public virtual string TitleForHeader(UITableView tableView, nint section)
{
return string.Empty;
}
[Foundation.Export("tableView:willDisplayCell:forRowAtIndexPath:")]
public virtual void WillDisplay(UIKit.UITableView tableView, UIKit.UITableViewCell cell, Foundation.NSIndexPath indexPath)
{
}
}
}
tableView should have a reference count of 2 (because of AddSubView and my property).
This is the main view controller, which instantiates SomeViewController:
public class MasterViewContainer : UIViewController
{
private bool hasSetupHandlersAndEvents = false;
// ...
public override void ViewWillAppear (bool animated)
{
base.ViewWillAppear (animated);
if (!hasSetupHandlersAndEvents) {
if (listButton != null) {
listButton.Clicked += listButton_Clicked;
}
hasSetupHandlersAndEvents = true;
}
}
public override void ViewWillDisappear (bool animated)
{
base.ViewWillDisappear (animated);
if (hasSetupHandlersAndEvents) {
if (listButton != null) {
listButton.Clicked -= listButton_Clicked;
}
hasSetupHandlersAndEvents = false;
}
}
private void listButton_Clicked(object sender, EventArgs args){
SomeViewController viewController = new SomeViewController();
viewController.SomeEvent += SomeEventHandler;
NavigationController.PushViewController(viewController, false);
}
}
As you can see SomeViewController has a reference to MasterViewContainer, because of SomeEventHandler.
SomeViewController is released if I use
public class SomeViewController : UITableViewController
, but it isn't released if I use
public class SomeViewController : HUDTableViewController
The Dispose method is never called. I don't see a reference cycle. Where do I have to release something? What I'm missing?
Try 1:
This is the only solution, which comes to my mind. I use a field (class variable) where I hold the reference to SomeViewController. In DidReceiveMemoryWarning I manually release/dispose it. When I want to access the field, I check if it has been initialised before. If not I initialise it when needed.
public class MasterViewContainer : UIViewController
{
private SomeViewController viewController;
public override void DidReceiveMemoryWarning ()
{
// Releases the view if it doesn't have a superview.
base.DidReceiveMemoryWarning ();
// Release any cached data, images, etc that aren't in use.
if (this.viewController != null)
{
this.viewController.SomeEvent -= SomeEventHandler;
this.viewController.Dispose();
this.viewController = null;
}
}
private void listButton_Clicked(object sender, EventArgs args){
if (this.viewController == null)
{
this.viewController = new SomeViewController();
this.viewController.SomeEvent += SomeEventHandler;
}
NavigationController.PushViewController(this.viewController, false);
}
But this solution isn't perfect. The dispose is also called when the view is currently on screen. So it is very likely to have malfunctions.
Bounty:
I'd like to have a solution, which explains the memory management issue. Why it doesn't get released? What has to change to get it released (without doing stuff like in my try). It should behave like UITableViewController.
Try 2:
Now I tried to override the Dispose(bool disposing) of HUDTableViewController:
protected override void Dispose(bool disposing)
{
if(!this.disposed)
{
if(disposing)
{
this.tableView.RemoveFromSuperview();
this.tableView.Dispose();
}
this.disposed = true;
}
base.Dispose(disposing);
}
Neither this Dispose method of HUDTableViewController nor the Dispose method of SomeViewController is called.

Call super if you are wanting your parent view to also call the same function handle your management from there. Depending on the arrangement you wouldn't need to do any other manual disposing.
public override void DidReceiveMemoryWarning ()
{
// If you want the superclass to fire the function first call super first
// and vice versa.
super.didReceiveMemoryWarning();
// Releases the view if it doesn't have a superview.
base.DidReceiveMemoryWarning ();

Related

Xamarin iOS black screen

I´m very new to Xamarin and currently I want to develop a little iOS app that receives data from a REST-Service.
So I have the following Storyboard:
In the table view there should be some entries that are consumed from the REST-Service. When you click on one row you should be "redirected" to a detail view which should be the right View.
The problem is, that the screen of the right story board is just black:
Well let´s have a look at my code, first the FinishedLaunching method in my AppDelegate.cs:
public override void FinishedLaunching(UIApplication application)
{
Window = new UIWindow(UIScreen.MainScreen.Bounds);
UIStoryboard storyboard;
UIViewController initialViewController;
var credential = CredentialController.Instance.FindAccount(CustomStaticLiterals.AppName);
if (credential == null)
{
storyboard = UIStoryboard.FromName("AccountCreationViewController", NSBundle.MainBundle);
initialViewController = storyboard.InstantiateInitialViewController() as UIViewController;
}
else
{
storyboard = UIStoryboard.FromName("OverviewViewController", NSBundle.MainBundle);
initialViewController = storyboard.InstantiateInitialViewController() as UIViewController;
}
Window.RootViewController = initialViewController;
Window.MakeKeyAndVisible();
}
Here is my ProjectOverviewController:
public partial class ProjectOverviewController : UITableViewController
{
public List<Project> Projects { get; set; }
private static readonly NSString callHistoryCellId = new NSString("ProjectCell");
public ProjectOverviewController(IntPtr handle) : base(handle)
{
TableView.RegisterClassForCellReuse(typeof(UITableViewCell), callHistoryCellId);
ProjectOverviewDataSource source = new ProjectOverviewDataSource(this);
source.DetailProjectEvent += DetailProjectPage;
TableView.Source = source;
Projects = new List<Project>();
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
var credentials = CredentialController.Instance.FindAccount(CustomStaticLiterals.AppName);
var service = new ServiceInvoker();
Projects = new List<Project>(service.GetCurrentProjectsOfUserAsync(credentials.UserName).Result);
}
public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
}
void DetailProjectPage(object sender, EventArgs e, int index)
{
var currentProject = Projects[index];
var projectViewController =
Storyboard.InstantiateViewController("ProjectViewController") as ProjectViewController;
if (projectViewController != null)
{
projectViewController.Initialize(currentProject);
NavigationController.PushViewController(projectViewController, true);
}
}
class ProjectOverviewDataSource : UITableViewSource
{
ProjectOverviewController controller;
public delegate void DetailProjectHandler(object sender, EventArgs e, int index);
public event DetailProjectHandler DetailProjectEvent;
public ProjectOverviewDataSource(ProjectOverviewController controller)
{
this.controller = controller;
}
// Returns the number of rows in each section of the table
public override nint RowsInSection(UITableView tableView, nint section)
{
return controller.Projects.Count;
}
//
// Returns a table cell for the row indicated by row property of the NSIndexPath
// This method is called multiple times to populate each row of the table.
// The method automatically uses cells that have scrolled off the screen or creates new ones as necessary.
//
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
var cell = tableView.DequeueReusableCell(ProjectOverviewController.callHistoryCellId);
int row = indexPath.Row;
cell.TextLabel.Text = controller.Projects[row].Header;
return cell;
}
public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
var index = indexPath.Row;
if (DetailProjectEvent != null)
{
DetailProjectEvent(this, new EventArgs(), index);
}
tableView.DeselectRow(indexPath, true);
}
}
}
And finally the the ProjectViewController:
public sealed partial class ProjectViewController : UIPageViewController
{
private Project masterModel;
public ProjectViewController (IntPtr handle) : base (handle)
{
}
public void Initialize(Project masterModel)
{
if (masterModel == null)
{
throw new ArgumentNullException(nameof(masterModel));
}
this.masterModel = masterModel;
}
public override void ViewDidLoad()
{
Title = masterModel.Header;
CustomerField = new UITextField();
CustomerField.Text = masterModel.Customer;
ObjectAddressField = new UITextField();
ObjectAddressField.Text = masterModel.Customer;
}
}
Well there is an other strange behaviour I realized:
When I wanted to set a text for the CustomerField.Text and ObjectAddress.Text property I got a NullReferenceException that the two objects CustomerField and ObjectAddressField are null which leads me to the conclusion that there must a wrong initialization of the ProjectViewController.
If you have some other recommendations about my code, feel free to tell my, because as I said I´m a rookie with Xamarin and App-Development.

How to handle accessory button tap on iOS in Xamarin.Forms?

There's a AccessoryButtonTapped method to override in table view delegate, but it's not clear how to perform that in a ListViewRenderer subclass?
So I can display a disclosure indicator, but can't handle tap on it.
public class ContactCellRenderer : ImageCellRenderer
{
public override UITableViewCell GetCell (
Cell item, UITableViewCell reusableCell, UITableView tv)
{
var cell = base.GetCell (item, reusableCell, tv);
cell.Accessory = UITableViewCellAccessory.DetailDisclosureButton;
return cell;
}
}
I think, you have just to implement the method AccessoryButtonTapped in your renderer.
public class ContactListViewRenderer : ListViewRenderer, IUITableViewDelegate
{
protected override void OnElementChanged(ElementChangedEventArgs<ListView> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.WeakDelegate = this; // or. Control.Delegate
}
}
public virtual void AccessoryButtonTapped(UITableView tableView, NSIndexPath indexPath)
{
// accessory tapped
}
}
In addition to Sven-Michael, you can enrich his code by creating a inheritance of your ListView (if you do not already have one) and add a Delegate to it like this:
public class AccessoryListView : ListView
{
public delegate void OnAccessoryTappedDelegate();
public OnAccessoryTappedDelegate OnAccessoryTapped { get; set; }
}
Now from your custom renderer - don't forget to set it to your new inherited ListView - call the delegate
public class ContactListViewRenderer : ListViewRenderer, IUITableViewDelegate
{
private AccessoryListView _formsControl;
protected override void OnElementChanged(ElementChangedEventArgs<AccessoryListView> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.WeakDelegate = this; // or. Control.Delegate
}
if (e.NewElement != null)
_formsControl = e.NewElement;
}
public virtual void AccessoryButtonTapped(UITableView tableView, NSIndexPath indexPath)
{
// accessory tapped
if (_formsControl.OnAccessoryTapped != null)
_formsControl.OnAccessoryTapped();
}
}
You can of course add some parameters in there to supply your shared code with more data. With this you do have some platform specific code, but you get back to your shared code 'as soon as possible' making your code more reusable.
Another sample of this with a Map control can be found here.

Error on app launch: Foundation.MonoTouchException: Objective-C exception thrown (Xamarin iOS)

I get this error message when launching my app:
Foundation.MonoTouchException: Objective-C exception thrown. Name:
NSInvalidArgumentException Reason: -[TableSource initWithCoder:]:
unrecognized selector sent to instance 0x796e6fa0
I already searched on google, but didn't find a solution.
About the app: The App has a UITableView with some custom cells. The UITableView is on a normal "view". Theres also a Button on the normal "view", this button should (when touched) add a custom cell to the UITableView.
The UITableView has the name "tableView" and in properties at class "TableSource". The Button has the name "btn01" and in properties as class "ViewController".
The custom cells have as "reuse identifier" "Cell01Reuse", "Cell02Reuse", etc. And as class "Testclass" (which doesnt exist as a file).
The View Controller (the base, where everything is on) has "ViewController" as class.
I have two classes with code. First is "View Controller":
using System;
using UIKit;
using Foundation;
using System.Collections.Generic;
namespace myapp
{
public partial class ViewController : UIViewController
{
public ViewController(IntPtr handle) : base(handle)
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
// Perform any additional setup after loading the view, typically from a nib.
//UITableView _table;
//_table = new UITableView
//{
// Frame = new CoreGraphics.CGRect(0, View.Bounds.Height * 0.03, View.Bounds.Width, View.Bounds.Height * 0.80),
// Source = new TableSource(null)
//};
//_table.SeparatorStyle = UITableViewCellSeparatorStyle.None;
//View.AddSubview(_table);
TableSource TS = new TableSource();
btn01.TouchUpInside += (sender, e) =>
{
TS.updateTableView();
string cell01 = "Cell01Reuse";
TS.tableItems.Add(cell01);
};
}
public override void DidReceiveMemoryWarning()
{
base.DidReceiveMemoryWarning();
// Release any cached data, images, etc that aren't in use.
}
}
}
Second is "TableSource":
using System;
using System.Collections.Generic;
using System.Text;
using Foundation;
using UIKit;
namespace myapp
{
public partial class TableSource : UITableViewSource
{
//string[] tableItems;
public List<string> tableItems = new List<string>();
public static string cellIdentifier = "TableCell";
//public TableSource(string[] items)
//{
// tableItems = items;
//}
public TableSource()
{
}
public override nint RowsInSection(UITableView tableview, nint section)
{
return 0;
}
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
UITableViewCell cell = tableView.DequeueReusableCell(cellIdentifier);
if (cell == null)
{
cell = new UITableViewCell(UITableViewCellStyle.Default, cellIdentifier);
}
cell.TextLabel.Text = tableItems[indexPath.Row];
tableItems.Add(Convert.ToString(cell));
return cell;
}
public override nint NumberOfSections(UITableView tableView)
{
return base.NumberOfSections(tableView);
}
public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
new UIAlertView("Alert", "You touched: " + tableItems[indexPath.Row], null, "OK", null).Show();
tableView.DeselectRow(indexPath, true);
}
public void updateTableView()
{
tableView.updateTableView();
}
}
}
Actually I can not reproduce the issue you met, your description is not clear enough, but there are some problem in you code is for sure, such as you should not return 0 in RowsInSection method, I can give you a sample to reference.(All the UI is created by code)
public partial class ViewController : UIViewController
{
protected ViewController (IntPtr handle) : base (handle)
{
// Note: this .ctor should not contain any initialization logic.
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
// Perform any additional setup after loading the view, typically from a nib.
CGRect tableFrame = this.View.Bounds;
tableFrame.Y = 100;
tableFrame.Height -= 100;
UITableView tableView = new UITableView (tableFrame);
this.View.AddSubview (tableView);
MyTalbeSource mySource = new MyTalbeSource ();
tableView.Source = mySource;
tableView.ReloadData ();
int count = 0;
UIButton btnNew = new UIButton (UIButtonType.System);
btnNew.Frame = new CGRect (20, 20, 100, 40);
btnNew.SetTitle ("NewItem", UIControlState.Normal);
btnNew.TouchUpInside += delegate {
mySource.AddNewItem ("NewItem" + count++);
tableView.ReloadData ();
};
this.Add (btnNew);
}
}
class MyTalbeSource : UITableViewSource
{
private const string CELL_ID = "MyTalbeCell";
private List<string> dataList;
public MyTalbeSource ()
{
dataList = new List<string> ();
for (int i = 0; i < 5; i++) {
dataList.Add ("Test " + i.ToString ());
}
}
public void AddNewItem (string title)
{
dataList.Add (title);
}
public override nint RowsInSection (UITableView tableview, nint section)
{
return dataList.Count;
}
public override UITableViewCell GetCell (UITableView tableView, Foundation.NSIndexPath indexPath)
{
MyTableCell cell = tableView.DequeueReusableCell (CELL_ID) as MyTableCell;
if (null == cell) {
cell = new MyTableCell (UITableViewCellStyle.Default, CELL_ID);
cell.InitCell ();
}
cell.Text = dataList [indexPath.Row];
return cell;
}
}
class MyTableCell : UITableViewCell
{
private UILabel lbInfo;
public string Text {
get {
return lbInfo.Text;
}
set {
lbInfo.Text = value;
}
}
public MyTableCell (UITableViewCellStyle style, string cellID) : base (style, cellID)
{
}
public void InitCell ()
{
lbInfo = new UILabel ();
lbInfo.TextAlignment = UITextAlignment.Center;
this.AddSubview (lbInfo);
}
public override void LayoutSubviews ()
{
lbInfo.Frame = this.Bounds;
}
}
Hope it can help you.
Any question about Xamarin.iOS is welcome.

Where or when to call RemoveObserver

I have a UITextView subclass where I add an NSNotificationCenter observer. But where do I remove the observer again?
My code:
_textDidChangeNotification = UITextView.Notifications.ObserveTextDidChange(TextDidChange);
In Objective C I would do it in the dealloc method but I am not sure where to do the same in C#
As I understand the documentation I should call
_textDidChangeNotification.Dispose()
I have tried to have a
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
_textDidChangeNotification.Dispose();
}
}
but it is never called.
The complete class, as requested:
public class PlaceholderTextView : UITextView
{
public string Placeholder
{
get { return PlaceholderLabel.Text; }
set
{
PlaceholderLabel.Text = value;
PlaceholderLabel.SizeToFit();
}
}
protected UILabel PlaceholderLabel { get; set; }
protected NSObject _textDidChangeNotification;
public override string Text
{
get
{
return base.Text;
}
set
{
base.Text = value;
AdjustPlaceholderHidden();
}
}
public PlaceholderTextView()
{
SetupLayout();
_textDidChangeNotification
= UITextView.Notifications.ObserveTextDidChange(TextDidChange);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
_textDidChangeNotification.Dispose();
}
protected void SetupLayout()
{
PlaceholderLabel = new UILabel(new CGRect(0, 9, 0, 0));
PlaceholderLabel.TextColor = UIColor.FromWhiteAlpha(0.702f, 1f);
AddSubview(PlaceholderLabel);
}
protected void AdjustPlaceholderHidden()
{
if (Text.Length > 0)
{
PlaceholderLabel.Hidden = true;
}
else
{
PlaceholderLabel.Hidden = false;
}
}
protected void TextDidChange(object sender, Foundation.NSNotificationEventArgs args)
{
AdjustPlaceholderHidden();
}
}
I would do it in ViewWillDisappear like so:
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear (animated);
SubscribeMessages ();
}
public override void ViewWillDisappear(bool animated)
{
base.ViewWillDisappear(animated);
UnSubscribeMessages ();
}
public void SubscribeMessages ()
{
_hideObserver = NSNotificationCenter.DefaultCenter.AddObserver(UIKeyboard.WillHideNotification, OnKeyboardNotification);
_showObserver = NSNotificationCenter.DefaultCenter.AddObserver(UIKeyboard.WillShowNotification, OnKeyboardNotification);
}
public void UnSubscribeMessages ()
{
if (_hideObserver != null) NSNotificationCenter.DefaultCenter.RemoveObserver (_hideObserver);
if (_showObserver != null) NSNotificationCenter.DefaultCenter.RemoveObserver(_showObserver);
}
or ViewDidDisappear like in the Xamarin sample code here
Update
I see what you mean now, I would suspect that something is preventing the custom view from being garbage collected. Have you had a look at this blog post it might help.
Also from this sample code it looks like you are calling the dispose correctly but they null out the custom view on ViewDidUnload here:

What is the best way to switch a UITableView from list to grouped?

I have a requirement where I initially have a list of messages only ordered by date/time. The requirement if for the user to be able to click on a UISegmentedControl (list of 4 buttons) and be able to change the UITableView from a straight list to a grouped list (ie. grouped by category of message).
From what I've read, once the style is set on a UITableView you can not change it. So what is the best approach to satisfy this requirement? Kill the view and re-create with the appropriate style?
Not that it makes a huge difference, I am using Xamarin Studio and C#, targeting Mono 3.2.1 and iOS 6+
Rather than killing the view and re-instantiating, just maintain references to two UITableViews, one of each of the appropriate types. Toggle between them using your Controller class. The following simple example puts the toggling button in the same UIView as the table, which is probably not appropriate, but otherwise shows the technique:
public class ChangeableSource : UITableViewSource
{
public bool Grouped { get; set; }
public override int NumberOfSections(UITableView tableView)
{
if(Grouped)
{
return 4;
}
else
{
return 1;
}
}
public override int RowsInSection(UITableView tableview, int section)
{
return 3;
}
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
var cell = tableView.DequeueReusableCell("Default");
if(cell == null)
{
cell = new UITableViewCell(UITableViewCellStyle.Default, "Default");
}
cell.TextLabel.Text = String.Format("IndexPath {0} {1}", indexPath.Section, indexPath.Row);
return cell;
}
}
public class ToggleTableView : UIView
{
UITableView ungroupedView;
UITableView groupedView;
ChangeableSource changeableSource;
public void SetStyle(bool grouped)
{
changeableSource.Grouped = grouped;
if(changeableSource.Grouped)
{
ungroupedView.RemoveFromSuperview();
AddSubview(groupedView);
}
else
{
groupedView.RemoveFromSuperview();
AddSubview(ungroupedView);
}
}
public bool GetStyle()
{
return changeableSource.Grouped;
}
public ToggleTableView()
{
var btn = new UIButton(new RectangleF(10, 10, 150, 40));
btn.SetTitle("Change", UIControlState.Normal);
btn.TouchUpInside += (s,e) => ToggleStyle(this, new EventArgs());
var tvFrame = new RectangleF(0, 60, UIScreen.MainScreen.Bounds.Width, UIScreen.MainScreen.Bounds.Height - 60);
ungroupedView = new UITableView(tvFrame, UITableViewStyle.Plain);
groupedView = new UITableView(tvFrame, UITableViewStyle.Grouped);
AddSubview(btn);
AddSubview(ungroupedView);
changeableSource = new ChangeableSource();
changeableSource.Grouped = false;
ungroupedView.Source = changeableSource;
groupedView.Source = changeableSource;
}
public event EventHandler<EventArgs> ToggleStyle = delegate {};
}
public class TogglingTableController : UIViewController
{
public TogglingTableController() : base ()
{
}
public override void DidReceiveMemoryWarning()
{
// Releases the view if it doesn't have a superview.
base.DidReceiveMemoryWarning();
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
var view = new ToggleTableView();
view.ToggleStyle += (s,e) =>
{
view.SetStyle(! view.GetStyle());
};
this.View = view;
}
}
[Register ("AppDelegate")]
public class AppDelegate : UIApplicationDelegate
{
UIWindow window;
TogglingTableController viewController;
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
window = new UIWindow(UIScreen.MainScreen.Bounds);
viewController = new TogglingTableController();
window.RootViewController = viewController;
window.MakeKeyAndVisible();
return true;
}
}
public class Application
{
static void Main(string[] args)
{
UIApplication.Main(args, null, "AppDelegate");
}
}

Categories