Reputation: 71
I am trying to add a UISwitch in every cell (this works). When I tap to toggle any switch other than the last one, they all give the last switches state until I change the last switches state
`public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath) {
//---- declare vars
UITableViewCell cell = tableView.DequeueReusableCell (this._cellIdentifier);
//---- if there are no cells to reuse, create a new one
if (cell == null) {
// This changes the style of the UITableViewCell to the Default style
cell = new UITableViewCell (UITableViewCellStyle.Default, this._cellIdentifier);
// Instantiate a cell accessory here
uiSwitch = new UISwitch (new RectangleF (0f, 0f, 20f, 20f));
uiSwitch.Tag = indexPath.Row;
uiSwitch.ValueChanged += (object sender, EventArgs e) => {
Console.WriteLine ("Cell Switch value is now {0}", uiSwitch.On);
};
_vRMs.View.AddSubview (uiSwitch);
// keep a reference to each cell you create,
// e.g. add them to a static List<UITableViewCell>.
// The GC won't be able to collect them so the event handler will work later.
cells.Add (cell);
}
//---- create a shortcut to our item
TableViewItem item = this._TableViewItemGroupList[indexPath.Section].Items[indexPath.Row];
cell.TextLabel.Text = item.Name;
cell.Accessory = UITableViewCellAccessory.DisclosureIndicator;
cell.AccessoryView = uiSwitch;
// cell.DetailTextLabel.Text = item.SubHeading;
return cell;
}`
I wanted to know if all this code was necessary to create a table with the UISwitches - being new to the iPhone dev world, I'm not sure. I'm hoping this update will help in my cause.
`using System;
using System.Drawing;
using System.Collections.Generic;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
namespace eOneRaw {
public partial class vRMs : UIViewController {
#region FIELDS
private string _ViewTitle = "RMs";
private UITableView _TableView;
private TableViewDataSource _TableViewDataSource;
private List<TableViewItemGroup> _TableViewItemGroupList;
private static vRMs _vRMs;
#endregion
#region PROPERTIES
#endregion
#region ViewDidLoad
public override void ViewDidLoad () {
base.ViewDidLoad ();
// Title the Controller
Title = _ViewTitle;
#region UITableView Setup
// Set up the table and data
this.CreateTableItems ();
// Create the UITableView
_TableView = new UITableView() {
Delegate = new TableViewDelegate(_TableViewItemGroupList),
DataSource = _TableViewDataSource,
AutoresizingMask = UIViewAutoresizing.FlexibleHeight | UIViewAutoresizing.FlexibleWidth,
};
_TableView.SizeToFit();
// Reposition and resize the receiver
_TableView.Frame = new RectangleF (0, 0, this.View.Frame.Width, this.View.Frame.Height);
// Add the table view as a subview
this.View.AddSubview(_TableView);
#endregion
#region Define the Look of the View
var _barbtnCancel = new UIBarButtonItem(UIBarButtonSystemItem.Done);
NavigationItem.LeftBarButtonItem = _barbtnCancel;
_barbtnCancel.Clicked += (s, e) => {
this.NavigationController.PopViewControllerAnimated(true);
};
#endregion
} // end ViewDidLoad
#endregion
#region METHODS
public vRMs () {
// Shouldn't ever happen
_vRMs = this;
Console.WriteLine (Environment.StackTrace);
}
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.
}
#endregion
#region ALL TABLE FUNCTIONALITY
#region CreateTableItems
//========================================================================
/// <summary>
/// Creates a set of table items.
/// </summary>
// This is where you define your table
protected void CreateTableItems () {
_TableViewItemGroupList = new List<TableViewItemGroup> ();
//---- declare vars
TableViewItemGroup tGroup;
tGroup = new TableViewItemGroup() { Name = "Regional Managers" };
tGroup.Items.Add (new TableViewItem() { Name = "Chris" });
tGroup.Items.Add (new TableViewItem() { Name = "Mike" });
tGroup.Items.Add (new TableViewItem() { Name = "Dan" });
tGroup.Items.Add (new TableViewItem() { Name = "Steve" });
_TableViewItemGroupList.Add (tGroup);
this._TableViewDataSource = new TableViewDataSource(_TableViewItemGroupList);
}
#endregion
#region CLASS TableViewDelegate
// The delegate manages the transitions from view-to-view
private class TableViewDelegate : UITableViewDelegate {
private List<TableViewItemGroup> _TableViewItemGroupList;
public TableViewDelegate(List<TableViewItemGroup> pList) {
this._TableViewItemGroupList = pList;
}
public override void RowSelected (UITableView tableView, NSIndexPath indexPath) {
return;
}
}
#endregion
#region CLASS TableViewDataSource
public class TableViewDataSource : UITableViewDataSource {
protected List<TableViewItemGroup> _TableViewItemGroupList;
string _cellIdentifier = "TableViewCell";
private static UISwitch uiSwitch;
static List<UITableViewCell> cells = new List<UITableViewCell> ();
public TableViewDataSource (List<TableViewItemGroup> items) {
this._TableViewItemGroupList = items;
}
/// <summary>
/// Called by the TableView to determine how many sections(groups) there are.
/// </summary>
public override int NumberOfSections (UITableView tableView) {
return this._TableViewItemGroupList.Count;
}
/// <summary>
/// Called by the TableView to determine how many cells to create for that particular section.
/// </summary>
public override int RowsInSection (UITableView tableview, int section) {
return this._TableViewItemGroupList[section].Items.Count;
}
/// <summary>
/// Called by the TableView to retrieve the header text for the particular section(group)
/// </summary>
public override string TitleForHeader (UITableView tableView, int section) {
return this._TableViewItemGroupList[section].Name;
}
/// <summary>
/// Called by the TableView to retrieve the footer text for the particular section(group)
/// </summary>
public override string TitleForFooter (UITableView tableView, int section) {
return this._TableViewItemGroupList[section].Footer;
}
#region UITableViewCell
/// <summary>
/// Called by the TableView to get the actual UITableViewCell to render for the particular section and row
/// </summary>
public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath) {
//---- declare vars
UITableViewCell cell = tableView.DequeueReusableCell (this._cellIdentifier);
//---- if there are no cells to reuse, create a new one
if (cell == null) {
// This changes the style of the UITableViewCell to the Default style
cell = new UITableViewCell (UITableViewCellStyle.Default, this._cellIdentifier);
// This changes the style of the UITableViewCell to the Subtitle style,
// which displays a second line of text within the cell.
// cell = new UITableViewCell (UITableViewCellStyle.Subtitle, this._cellIdentifier);
// Instantiate a cell accessory here
uiSwitch = new UISwitch (new RectangleF (0f, 0f, 20f, 20f));
uiSwitch.Tag = indexPath.Row;
uiSwitch.ValueChanged += (object sender, EventArgs e) => {
Console.WriteLine ("Cell Switch value is now {0}", uiSwitch.On);
};
_vRMs.View.AddSubview (uiSwitch);
// keep a reference to each cell you create,
// e.g. add them to a static List<UITableViewCell>.
// The GC won't be able to collect them so the event handler will work later.
cells.Add (cell);
}
//---- create a shortcut to our item
TableViewItem item = this._TableViewItemGroupList[indexPath.Section].Items[indexPath.Row];
cell.TextLabel.Text = item.Name;
cell.Accessory = UITableViewCellAccessory.DisclosureIndicator;
cell.AccessoryView = uiSwitch;
// cell.DetailTextLabel.Text = item.SubHeading;
// Add an image if needed
/*
if(!string.IsNullOrEmpty(item.ImageName))
{
cell.ImageView.Image = UIImage.FromFile("Images/" + item.ImageName );
}
*/
return cell;
}
#endregion
} // end TableViewDataSource Class
#endregion
#region CLASS TableViewItemGroup
//========================================================================
/// <summary>
/// A group that contains table items
/// </summary>
public class TableViewItemGroup {
public string Name { get; set; }
public string Footer { get; set; }
public List<TableViewItem> Items {
get { return this._items; }
set { this._items = value; }
}
protected List<TableViewItem> _items = new List<TableViewItem>();
public TableViewItemGroup () {
}
}
#endregion
#region CLASS TableViewItem
//========================================================================
/// <summary>
/// Represents our item in the table
/// </summary>
public class TableViewItem {
public string Name { get; set; }
public string SubHeading { get; set; }
public string ImageName { get; set; }
public TableViewItem () {
}
}
#endregion
#endregion
#region OBSOLETE methods
// ***************************** OBSOLETE
// ***************************** OBSOLETE
// ***************************** OBSOLETE
[Obsolete]
public override void ViewDidUnload () {
base.ViewDidUnload ();
// Clear any references to subviews of the main view in order to
// allow the Garbage Collector to collect them sooner.
//
// e.g. myOutlet.Dispose (); myOutlet = null;
ReleaseDesignerOutlets ();
}
[Obsolete]
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation) {
// Return true for supported orientations
return (toInterfaceOrientation != UIInterfaceOrientation.PortraitUpsideDown);
}
#endregion
}
}`
Upvotes: 0
Views: 774
Reputation: 32694
In addition to the problems pointed out by Stuart, the other problem is that you are recycling the cells, so you might end up with a recycled cell that is pointing to another state, nto what you wanted.
For a case like this, you could just use a unique key for each UISlider that you create to ensure that you never reuse a UISlider for two different variables. Alternatively, you need to change your code so that the handler tells the different based on the IndexPath that acted on it.
Upvotes: 1
Reputation: 66882
There are a few problems with your code.
Firstly, I think your code sample misses a vital part?
What is the scope of the UISwitch variable? It seems like it's a class level reference?
Secondly, I think your code doesn't really handle cell reuse very well - the line uiSwitch.Tag = indexPath.Row;
isn't called in the case of reuse.
Thirdly, I'm not too sure that your approach is really very scalable - although it would work for small lists
In all honestly, you are probably better off just creating a custom cell for this switch - and then using the values from those custom cells... To create a custom cell, see:
Upvotes: 1