i would like to make a verification on/off button to show is the student verified. Once the switch is turn on in the "AddStudentViewController", a checkmark will show at the right hand side of the specific student's row in the table list in "StudentDataBaViewController". May i know how to do that?
**Additional Information:
1)StudentDataBaViewContoller (1st page of the app) is a TableViewController
2)AddStudentViewController (2nd page of the app) is a normal View Controller
Both are connected with a Push Segue named "StuSegue"
Below attached the code of my 2 view controller:
Code for "StudentDataBaViewController":
using Foundation;
using System;
using UIKit;
using SQLite;
using System.Collections.Generic;
using System.IO;
namespace One
{
public partial class StudentDataBaViewController : UITableViewController
{
private string pathToDatabase;
private List<Student> students;
public StudentDataBaViewController (IntPtr handle) : base (handle)
{
students = new List<Student>();
}
/*public override void PrepareForSegue(UIStoryboardSegue segue, NSObject sender)
{
if (segue.Identifier == "StuSegue")
{ // set in Storyboard
var navctlr = segue.DestinationViewController as AddStudentViewController;
if (navctlr != null)
{
var source = TableView.Source as StudentDataBaViewController;
var rowPath = TableView.IndexPathForSelectedRow;
var item = source.GetItem(rowPath.Row);
navctlr.SetTask(this, item); // to be defined on the TaskDetailViewController
}
}
}
*/
//connect to student_da.db database file and create a table named Student
public override void ViewDidLoad()
{
base.ViewDidLoad();
//path of the database
var documentsFolder = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
pathToDatabase = Path.Combine(documentsFolder, "student_db.db");
//connect database and create table
using (var connection = new SQLite.SQLiteConnection(pathToDatabase))
{
connection.CreateTable<Student>();
}
}
//used to relaod or update new elements entered on the list
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
students = new List<Student>();
using (var connection = new SQLite.SQLiteConnection(pathToDatabase))
{
var query = connection.Table<Student>();
foreach (Student student in query)
{
students.Add(student);
TableView.ReloadData();
}
}
}
public override nint RowsInSection(UITableView tableView, nint section)
{
return students.Count;
}
//make elements to be display on the database list
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
UITableViewCell cell = tableView.DequeueReusableCell("student");
var data = students[indexPath.Row];
cell.TextLabel.Text = data.StudentName;
cell.DetailTextLabel.Text = data.StudentId;
return cell;
}
public override bool CanEditRow(UITableView tableView, NSIndexPath indexPath)
{
return true;
}
public override void CommitEditingStyle(UITableView tableView, UITableViewCellEditingStyle editingStyle, Foundation.NSIndexPath indexPath)
{
switch (editingStyle)
{
case UITableViewCellEditingStyle.Delete:
// remove the item from the underlying data source
students.RemoveAt(indexPath.Row);
// delete the row from the table
tableView.DeleteRows(new NSIndexPath[] { indexPath }, UITableViewRowAnimation.Fade);
break;
case UITableViewCellEditingStyle.None:
Console.WriteLine("CommitEditingStyle:None called");
break;
}
}
}
public class Student
{
[PrimaryKey]
public string StudentId
{
get;
set;
}
public string StudentName
{
get;
set;
}
public string StudentPassword
{
get;
set;
}
public bool StudentAttendence
{
get;
set;
}
}
}
Code for "AddStudentViewController":
using Foundation;
using System;
using System.IO;
using UIKit;
namespace One
{
public partial class AddStudentViewController : UIViewController
{
private string pathToDatabase;
//used to access same database to grab data for display
protected AddStudentViewController (IntPtr handle) : base (handle)
{
// Note: this .ctor should not contain any initialization logic.
var documentsFolder = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
pathToDatabase = Path.Combine(documentsFolder, "student_db.db");
}
// create a function for save button
public override void ViewDidLoad()
{
base.ViewDidLoad();
// Perform any additional setup after loading the view, typically from a nib.
saveStudent.Clicked += SaveButton_Clicked;
}
public override void DidReceiveMemoryWarning()
{
base.DidReceiveMemoryWarning();
// Release any cached data, images, etc that aren't in use.
}
//create connection with database and make handler for save button and insert the element into database
void SaveButton_Clicked(object sender, EventArgs e)
{
using (var connection = new SQLite.SQLiteConnection(pathToDatabase))
{
connection.Insert(new Student() { StudentName = AddStuNameTxt.Text, StudentId = AddStuIdTxt.Text, StudentPassword = AddStuPassTxt.Text, StudentAttendence =true });
new UIAlertView("Updated !", "Student successfully created", null, "OK", null).Show();
}
//navigate page back to database list
NavigationController.PopToRootViewController(true);
}
}
}
According to my understanding, you are hoping refushing the UI in "StudentDataBaViewController" after the switch is turn on in the "AddStudentViewController".
you can use delegate to send message between two controllers.
Related
may I know how to make the rows of my table can be swipe to delete or pop out a "red stop" button to allow user to delete the inserted data?
Below attached with the code of my Table ViewController cs file that only displays all data in table list :
*The view controller is created using storyboard, not by code.
using Foundation;
using System;
using UIKit;
using SQLite;
using System.Collections.Generic;
using System.IO;
namespace One
{
public partial class StudentDataBaViewController : UITableViewController
{
private string pathToDatabase;
private List<Student> students;
public StudentDataBaViewController (IntPtr handle) : base (handle)
{
students = new List<Student>();
}
//connect to student_da.db database file and create a table named Student
public override void ViewDidLoad()
{
base.ViewDidLoad();
//path of the database
var documentsFolder = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
pathToDatabase = Path.Combine(documentsFolder, "student_db.db");
//connect database and create table
using (var connection = new SQLite.SQLiteConnection(pathToDatabase))
{
connection.CreateTable<Student>();
}
}
//used to relaod or update new elements entered on the list
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
students = new List<Student>();
using (var connection = new SQLite.SQLiteConnection(pathToDatabase))
{
var query = connection.Table<Student>();
foreach (Student student in query)
{
students.Add(student);
TableView.ReloadData();
}
}
}
public override nint RowsInSection(UITableView tableView, nint section)
{
return students.Count;
}
//make elements to be display on the database list
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
UITableViewCell cell = tableView.DequeueReusableCell("student");
var data = students[indexPath.Row];
cell.TextLabel.Text = data.StudentName;
cell.DetailTextLabel.Text = data.StudentId;
return cell;
}
public override bool CanEditRow(UITableView tableView, NSIndexPath indexPath)
{
return true;
}
}
public class Student
{
[PrimaryKey]
public string StudentId
{
get;
set;
}
public string StudentName
{
get;
set;
}
public string StudentPassword
{
get;
set;
}
public bool StudentAttendence
{
get;
set;
}
}
}
Add the following methods
public override void CommitEditingStyle (UITableView tableView,UITableViewCellEditingStyle editingStyle, Foundation.NSIndexPath indexPath){
switch (editingStyle) {
case UITableViewCellEditingStyle.Delete:
// remove the item from the underlying data source
tableItems.RemoveAt(indexPath.Row);
// delete the row from the table
tableView.DeleteRows (new NSIndexPath[] { indexPath }, UITableViewRowAnimation.Fade);
break;
case UITableViewCellEditingStyle.None:
Console.WriteLine ("CommitEditingStyle:None called");
break;
}}
In addition to overriding the getcell method , you need to provide CommitEditingStyle
public override void CommitEditingStyle (UITableView tableView, UITableViewCellEditingStyle editingStyle, MonoTouch.Foundation.NSIndexPath indexPath)
{
switch (editingStyle) {
case UITableViewCellEditingStyle.Delete:
// remove the item from the underlying data source
tableItems.RemoveAt(indexPath.Row);
// delete the row from the table
tableView.DeleteRows (new NSIndexPath[] { indexPath }, UITableViewRowAnimation.Fade);
break;
default:
break;
}
}
I have a problem with refreshing a UITableView correctly, at least the first time of ViewWillAppear and sometimes (rarely) might even hang the app. When I navigate away from the UIViewController with changing tab item and navigate back, everything starts working perfectly for the entire lifecycle..
Having a ReactiveTableViewSource like below.
public class ATableViewSource : ReactiveTableViewSourceBase<IAViewModel>
{
WeakReference<AListViewController> _weakContainer;
Lazy<AListViewController> _lazyContainerViewController;
AListViewController Container => _lazyContainerViewController.Value;
public ATableViewSource(AListViewController container,
UITableView tableView,
IReactiveNotifyCollectionChanged<IAViewModel> collection)
: base(tableView, collection,
ATableViewCell.Key,
ATableViewCell.Height,
ATableViewCell.Height)
{
_weakContainer = new WeakReference<AListViewController>(container);
tableView.RegisterNibForCellReuse(ATableViewCell.Nib, ATableViewCell.Key);
_lazyContainerViewController = new Lazy<AListViewController>(() =>
{
AListViewController _container;
_weakContainer.TryGetTarget(out _container);
return _container;
});
}
public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
base.RowSelected(tableView, indexPath);
tableView.DeselectRow(indexPath, false);
var item = ItemAt(indexPath) as IAViewModel;
if (item.IsNotNull())
{
AViewController viewController = new AViewController(item);
Container.NavigationController.PushViewController(viewController, true);
}
}
}
In AListViewController.ViewDidLoad I have this setup.
ATableViewSource _viewSource;
public override void ViewDidLoad()
{
base.ViewDidLoad();
TableView.RowHeight = UITableView.AutomaticDimension;
TableView.EstimatedRowHeight = 350.0f;
TableView.ContentInset = new UIEdgeInsets(8.0f, 0.0f, 8.0f, 0.0f);
_viewSource = new ATableViewSource(this, TableView, ViewModel.TheReactiveList);
TableView.Source = _viewSource;
}
And in ViewWillAppear I always refresh the data (ViewModel.TheReactiveList).
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
ViewModel.RefreshTheReactiveList();
}
The AViewModel setup.
public class TheListViewModel : SchedulersViewModelBase, ITheListViewModel
{
public ReactiveList<IAViewModel> TheReactiveList { get; } = new ReactiveList<IAViewModel> { ChangeTrackingEnabled = true };
protected readonly IDataService DataService;
public TheListViewModel(IScheduler mainScheduler,
IScheduler taskPoolScheduler,
IDataService dataService)
: base(mainScheduler, taskPoolScheduler)
{
DataService = dataService;
}
public void RefreshTheReactiveList()
{
DataService.RefreshData()
.SubscribeOn(MainScheduler)
.ObserveOn(MainScheduler)
.Subscribe(ClearDataAndAddRange,
ex => AppObservables.Errors.OnNext(ex))
.DisposeWith(Disposables);
}
void ClearDataAndAddRange(IEnumerable<IAViewModel> data)
{
using (TheReactiveList.SuppressChangeNotifications())
{
TheReactiveList.Clear();
TheReactiveList.AddRange(data);
}
}
}
I have to mention in this use case I have a parent UIViewController with two child controllers each with the same setup (UITableView, ReactiveTableViewSource, ViewModel.ReactiveList) and Hidden state is controlled for their UIView containers, but I noticed similar effects to UIViewController with one UITableView taking up to 3 seconds to show the results in the UITableView.
For your reference I am posting the ReactiveTableViewSourceBase<TViewModel> below, I have found this long time ago on the internet, so it might be suspicious. Changing the base class to a ReactiveTableViewSource<TViewModel> doesn't really make any difference though.
public abstract class ReactiveTableViewSourceBase<TViewModel> : ReactiveTableViewSource<TViewModel>, IInformsEnd
{
private readonly Subject<Unit> _requestMoreSubject = new Subject<Unit>();
private readonly Subject<CGPoint> _scrollSubject = new Subject<CGPoint>();
public IObservable<CGPoint> DidScroll
{
get { return _scrollSubject.AsObservable(); }
}
public IObservable<Unit> RequestMore
{
get { return _requestMoreSubject; }
}
public override void Scrolled(UIScrollView scrollView)
{
_scrollSubject.OnNext(scrollView.ContentOffset);
}
~ReactiveTableViewSourceBase()
{
Console.WriteLine("Destorying " + GetType().Name);
}
protected ReactiveTableViewSourceBase(UITableView tableView, nfloat height, nfloat? heightHint = null)
: base(tableView)
{
tableView.RowHeight = height;
tableView.EstimatedRowHeight = heightHint ?? tableView.EstimatedRowHeight;
}
protected ReactiveTableViewSourceBase(UITableView tableView, IReactiveNotifyCollectionChanged<TViewModel> collection,
Foundation.NSString cellKey, nfloat height, nfloat? heightHint = null, Action<UITableViewCell> initializeCellAction = null)
: base(tableView, collection, cellKey, (float)height, initializeCellAction)
{
tableView.RowHeight = height;
tableView.EstimatedRowHeight = heightHint ?? tableView.EstimatedRowHeight;
}
public override void WillDisplay(UITableView tableView, UITableViewCell cell, Foundation.NSIndexPath indexPath)
{
if (indexPath.Section == (NumberOfSections(tableView) - 1) &&
indexPath.Row == (RowsInSection(tableView, indexPath.Section) - 1))
{
// We need to skip an event loop to stay out of trouble
BeginInvokeOnMainThread(() => _requestMoreSubject.OnNext(Unit.Default));
}
}
public override void RowSelected(UITableView tableView, Foundation.NSIndexPath indexPath)
{
var item = ItemAt(indexPath) as ICanGoToViewModel;
if (item != null)
{
item.GoToCommand.Execute();
}
base.RowSelected(tableView, indexPath);
}
protected override void Dispose(bool disposing)
{
_requestMoreSubject.Dispose();
_scrollSubject.Dispose();
base.Dispose(disposing);
}
}
public interface IInformsEnd
{
IObservable<Unit> RequestMore { get; }
}
I am trying to bind grouped data to a table, but when I run the code the binding seems to be trying to create a cell for the Section level items rather than creating a section with the cells behind it.
First, I create my table:
table = new UITableView(CGRect.Empty, UITableViewStyle.Grouped);
table.RowHeight = UxConstants.UiDimensions.Dimension48;
table.AutoresizingMask = UIViewAutoresizing.All;
table.ScrollEnabled = true;
then I create my view source and bind it:
var source = new OperationalInfoTableViewSource(table);
table.Source = source;
var set = this.CreateBindingSet<IncidentInformationView, IncidentInformationViewModel>();
set.Bind(source).For(vm => vm.ItemsSource).To(vm => vm.TableSourceItem);
set.Apply();
I'm using a simplified class at the moment; so the binding target (TableSourceItem) is currently defined as:
public ObservableCollection<Stuff> TableSourceItem
{
get
{
return tableSourceItem;
}
set
{
tableSourceItem = value;
RaisePropertyChanged(() => TableSourceItem);
}
}
and the 'Stuff' class is simply
public class Stuff
{
public string Title {
get;
set;
}
public List<string> Items {
get;
set;
}
}
When I declare my data :
var items = new List<Stuff>();
items.Add(new Stuff { Title = "Group 1", Items = new List<string> { "Item 1", "Item 2" } });
items.Add(new Stuff { Title = "Group 2", Items = new List<string> { "Item 4", "Item 5"} });
TableSourceItem = new ObservableCollection<Stuff>(items);
The final bit of Code, is the table view source I have defined. This inherits from the MvxStandardTableView source:
public class OperationalInfoTableViewSource : MvxStandardTableViewSource
{
List<Stuff> items;
public OperationalInfoTableViewSource(UITableView tableView) : base (tableView)
{
TableView.RegisterClassForCellReuse (typeof(OperationalInfoViewCell), OperationalInfoViewCell.Key);
}
public override System.Collections.IEnumerable ItemsSource
{
get
{
return items;
}
set
{
if (value != null)
{
items = new List<Stuff>();
foreach (Stuff item in value)
{
items.Add(item);
}
base.ItemsSource = items;
}
}
}
public override string TitleForHeader(UITableView tableView, nint section)
{
return "Header";
}
public override nint NumberOfSections(UITableView tableView)
{
var i = items == null ? 0 : items.Count();
Mvx.Trace(String.Format( "Number of Sections {0}", i ));
return i;
}
public override nint RowsInSection(UITableView tableview, nint section)
{
return items == null ? 0 : items[(int)section].Items.Count();
}
public override bool CanEditRow(UITableView tableView, NSIndexPath indexPath)
{
return false;
}
public override bool CanPerformAction(UITableView tableView, ObjCRuntime.Selector action, NSIndexPath indexPath, NSObject sender)
{
return false;
}
public override bool CanMoveRow(UITableView tableView, NSIndexPath indexPath)
{
return false;
}
protected override UITableViewCell GetOrCreateCellFor(UITableView tableView, NSIndexPath indexPath, object item)
{
var cell = tableView.DequeueReusableCell(OperationalInfoViewCell.Key);
return cell;
}
public override nfloat GetHeightForHeader(UITableView tableView, nint section)
{
return UxConstants.UiDimensions.Dimension32;
}
public override UIView GetViewForHeader(UITableView tableView, nint section)
{
var operationalInfoTitle = new UILabel()
{
Lines = 1,
Font = UxConstants.UxFonts.MediumBold,
TextColor = UxConstants.UxColours.BBlue,
Text = "Guidance & Info"
};
var operationalInfoTitleDivider = new UIView()
{
BackgroundColor = UxConstants.UxColours.MGrey
};
var operationalInfoListView = new UIView();
operationalInfoListView.AddSubviews(operationalInfoTitle, operationalInfoTitleDivider);
operationalInfoListView.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints();
operationalInfoListView.AddConstraints(operationalInfoTitle.FullWidthOf(operationalInfoListView, UxConstants.UiDimensions.Dimension16));
operationalInfoListView.AddConstraints(operationalInfoTitleDivider.FullWidthOf(operationalInfoListView, UxConstants.UiDimensions.Dimension16));
operationalInfoListView.AddConstraints(
operationalInfoTitle.Height().EqualTo(UxConstants.UiDimensions.Dimension32),
operationalInfoTitle.AtTopOf(operationalInfoListView),
operationalInfoTitleDivider.Below(operationalInfoTitle),
operationalInfoTitleDivider.Height().EqualTo(2));
return operationalInfoListView;
}
}
I would expect 2 sections, each with two cells, but its seems to be creating one cell per Stuff class rather than one section per Stuff class.
Any ideas?
Found out the issue, I have failed to implement the important override:
protected override object GetItemAt(NSIndexPath indexPath)
{
if (items == null)
{
return null;
}
return items[indexPath.Section].Items.ElementAt((int)indexPath.Item);
}
Once I had included this method override it worked fine!
I'm working on some Xamarin examples of my own and to get a better understanding of making iOS apps and C# coding (I have more experience with Android programming).
I have a View where I'm displaying a Collection View and two Buttons, by pressing either I make a HTTP request to Imgur and retrieve different set of images. These images I want to display in the Collection View.
I make the requests with the following method in my Controller:
public void makeRequest(string url){
var request = (HttpWebRequest)WebRequest.Create(url);
request.Headers.Add ("Authorization", "Client-ID " + clientId);
request.Method = "GET";
Task<WebResponse> task = Task.Factory.FromAsync (
request.BeginGetResponse,
asyncResult => request.EndGetResponse (asyncResult),
(object)null);
task.ContinueWith (t => ReadStreamFromResponse (t.Result));
}
To parse the JSON response I use this method (I'm only interested in images, not albums):
private void ReadStreamFromResponse(WebResponse response){
using (Stream responseStream = response.GetResponseStream ()) {
using (StreamReader sr = new StreamReader (responseStream)) {
string content = sr.ReadToEnd ();
var json = JsonObject.Parse (content);
var array = json ["data"];
foreach (JsonObject o in array) {
string url = o ["link"];
bool isAlbum = o ["is_album"];
if (!isAlbum) {
url = url.Insert (url.Length - 4, "s");
AddElement (url);
}
}
}
}
}
}
The method I use to try to add the Image to the Source is the following:
public void AddElement(string url){
using (var imgUrl = new NSUrl (url)) {
using (var data = NSData.FromUrl (imgUrl)) {
photoSource.photos.Add (UIImage.LoadFromData (data));
InvokeOnMainThread (delegate {
PhotoCollection.ReloadData ();
});
}
}
}
This is my Source class:
class CollectionSource : UICollectionViewSource
{
public List<UIImage> photos;
public CollectionSource(){
photos = new List<UIImage> ();
}
public CollectionSource(List<UIImage> photos){
this.photos = photos;
}
public override UICollectionViewCell GetCell(UICollectionView collectionView, NSIndexPath indexPath){
var photoCell = (ImageCell)collectionView.DequeueReusableCell ((NSString) ImageCell.CELLID, indexPath);
var photo = photos [indexPath.Row];
photoCell.ImageView.Image = photo;
return photoCell;
}
public override int GetItemsCount(UICollectionView collectionView, int section){
return photos.Count;
}
public override int NumberOfSections(UICollectionView collectionView){
return 1;
}
public override void ItemHighlighted(UICollectionView collectionView, NSIndexPath indexPath){
var cell = collectionView.CellForItem (indexPath);
cell.ContentView.BackgroundColor = UIColor.Yellow;
}
public override void ItemUnhighlighted(UICollectionView collectionView, NSIndexPath indexPath){
var cell = collectionView.CellForItem (indexPath);
cell.ContentView.BackgroundColor = UIColor.White;
}
public override bool ShouldHighlightItem(UICollectionView collectionView, NSIndexPath indexPath){
return true;
}
public override bool ShouldShowMenu(UICollectionView collectionView, NSIndexPath indexPath){
return true;
}
public override bool CanPerformAction(UICollectionView collectionView, MonoTouch.ObjCRuntime.Selector action, NSIndexPath indexPath, NSObject sender){
return true;
}
public override void PerformAction(UICollectionView collectionView, MonoTouch.ObjCRuntime.Selector action, NSIndexPath indexPath, NSObject sender){
Console.WriteLine ("Perform action");
}
}
I avoided the use of CollectionView controller because I don't like to leave multiple operations to one class only, I like to split my code in classes.
This is my cell class:
public class ImageCell : UICollectionViewCell
{
public const string CELLID = "ImageCell";
[Export ("initWithFrame:")]
public ImageCell (System.Drawing.RectangleF frame) : base(frame){
this.Initialize ();
}
public UIImageView ImageView {
get;
set;
}
private void Initialize(){
// this.ImageView = new UIImageView (this.ContentView.Bounds);
this.ImageView = new UIImageView (UIImage.FromBundle("placeholder.png"));
this.ContentView.AddSubview (this.ImageView);
}
}
Finally this is my View Controller class:
partial class ViewController3 : UIViewController
{
public CollectionSource photoSource;
public ViewController3 (IntPtr handle) : base (handle)
{
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
PhotoCollection.RegisterClassForCell (typeof(ImageCell), (NSString)ImageCell.CELLID);
photoSource = new CollectionSource ();
PhotoCollection.Source = photoSource;
makeRequest ();
}
// makeRequest, ReadStreamFromResponse and AddElement are located below this method, I won't place them again
}
As you can see I based my code on the Introduction to Collection Views article found on Xamarin guides. I was successful in downloading remote images now but they're not properly displayed on the Collection View.
The images are downloaded but as they are downloaded they flash across the Collection View and the result end look like this:
For some reason not all of the cell render the image correctly, perhaps am I wrongly refreshing my CollectionView?
So I found a solution to my problem but I have no idea why did it make it work.
On my ImageCell class I added the following line of code to the Initialize method:
private void Initialize(){
this.ImageView = new UIImageView ();
this.ImageView.AutoresizingMask = ~UIViewAutoresizing.None;
// if no image is assigned to the ImageView, then the cell won't be rendered correctly if later you add the image
// not familiar with iOS guidelines so I don't know if that is the real reason
this.ImageView = new UIImageView (UIImage.FromBundle("temp.png"));
this.ContentView.AddSubview (this.ImageView);
}
With this the images are rendered correctly in the cells, still must improve the way I load this remote images but that's it, if you notice your cells aren't rendered correctly in place, then perhaps you should check if any component in your cell requires a placeholder to avoid leaving it empty.
I have been trying to implement a multi column table view by combining multiple UITableViews.
One problem I have run into, is that I am unable to get the override of RowSelected to be called when I select a row on one of the TableViews in my multi column view.
When running in the simulator, It highlights a row when clicked, so the ability to click a row is working, however the override is not called.
Below is the code for the UITableViewSource. Under that is the code that sets up the multi column view.
Any help would be greatly appreciated.
public class TableSource : UITableViewSource
{
protected List<object> _tableItems;
protected string cellIdentifier = "TableCell";
private string _propertyName;
public TableSource (List<object> items, string propertyName)
{
_tableItems = items;
_propertyName = propertyName;
}
public override int RowsInSection (UITableView tableview, int section)
{
return _tableItems.Count;
}
public override UITableViewCell GetCell (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
{
// request a recycled cell to save memory
UITableViewCell cell = tableView.DequeueReusableCell (cellIdentifier);
// if there are no cells to reuse, create a new one
if (cell == null)
cell = new UITableViewCell (UITableViewCellStyle.Default, cellIdentifier);
PropertyInfo property = _tableItems [indexPath.Row].GetType ().GetProperty (_propertyName);
cell.TextLabel.Text = property.GetValue(_tableItems[indexPath.Row]).ToString();
cell.UserInteractionEnabled = true;
return cell;
}
public override UIView GetViewForHeader (UITableView tableView, int section)
{
// NOTE: Don't call the base implementation on a Model class
// see http://docs.xamarin.com/guides/ios/application_fundamentals/delegates,_protocols,_and_events
throw new NotImplementedException ();
}
public override void RowDeselected (UITableView tableView, NSIndexPath indexPath)
{
// NOTE: Don't call the base implementation on a Model class
// see http://docs.xamarin.com/guides/ios/application_fundamentals/delegates,_protocols,_and_events
throw new NotImplementedException ();
}
public override void RowHighlighted (UITableView tableView, NSIndexPath rowIndexPath)
{
// NOTE: Don't call the base implementation on a Model class
// see http://docs.xamarin.com/guides/ios/application_fundamentals/delegates,_protocols,_and_events
throw new NotImplementedException ();
}
public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
new UIAlertView("Row Selected", "", null, "OK", null).Show();
tableView.DeselectRow (indexPath, true);
}
}
[Register("MultiColumnTableView")]
public class MultiColumnTableView: UIView
{
List<SingleColumnView> _tableViews;
IEnumerable<object> _dataSource;
SingleColumnView scrollingTable = null;
int _nextColumnX;
public MultiColumnTableView(){
}
public MultiColumnTableView (IntPtr handle):base(handle)
{
}
public IEnumerable<object> DataSource
{
get
{
return _dataSource;
}
set
{
_dataSource = value;
}
}
public void AddColumn(string columnName, string propertyName, int width)
{
if(_tableViews== null)
_tableViews = new List<SingleColumnView>();
var newColumn = new SingleColumnView (columnName, propertyName, _dataSource, width, _nextColumnX);
this.AddSubview (newColumn);
_tableViews.Add (newColumn);
_nextColumnX += (width);
newColumn.Scrolled += Scrolled;
foreach(var table in _tableViews)
{
table.ShowsVerticalScrollIndicator = false;
}
_tableViews.Last ().ShowsVerticalScrollIndicator = true;
}
public void AddColumn(string columnName, string[] propertyNames, string format)
{
if(_tableViews== null)
_tableViews = new List<SingleColumnView>();
var column = new SingleColumnView (columnName, propertyNames, format, _dataSource);
_tableViews.Add (column);
column.Scrolled += Scrolled;
foreach(var table in _tableViews)
{
table.ShowsVerticalScrollIndicator = false;
table.AllowsSelection = true;
}
_tableViews.Last ().ShowsVerticalScrollIndicator = true;
}
private void Scrolled (object sender, EventArgs args)
{
if (scrollingTable == null) {
scrollingTable = sender as SingleColumnView;
}
if(scrollingTable != _tableViews.Last())
_tableViews.Last().FlashScrollIndicators();
foreach (var table in _tableViews) {
if (table != sender) {
table.ContentOffset = (sender as SingleColumnView).ContentOffset;
}
}
scrollingTable = null;
}
}
public class SingleColumnView: UITableView
{
public IEnumerable<object> _dataSource;
public string _propertyName;
public string[] _propertyNames;
public string _format;
public string _columnName;
public SingleColumnView(string columnName, string propertyName, IEnumerable<object> dataSource, int width, int offsetX):base(new RectangleF(offsetX,0,width,500))
{
_columnName = columnName;
_propertyName = propertyName;
_dataSource = dataSource;
this.Source = new TableSource (dataSource.ToList(), propertyName);
//this.BackgroundColor = new UIColor(new MonoTouch.CoreGraphics.CGColor(255,0,0));
//this.SeparatorStyle = UITableViewCellSeparatorStyle.None;
this.SeparatorInset = UIEdgeInsets.Zero;
}
public SingleColumnView(string columnName, string[] propertyNames, string format, IEnumerable<object> dataSource):base()
{
_columnName = columnName;
_propertyNames = propertyNames;
_format = format;
_dataSource = dataSource;
}
}
How are you implementing the custom UITableViewDelegate? I would suggest using Monotouch's UITableViewSource as it combines both the UITableViewDataSource and the UITableViewDelegate into one file which makes things so much easier.
Source:more details
Add to You project
I think you should try using WeakDelegate to make this work.