I am using MvvmCross for my Xamarin iOS project. For my tableview source I have say, a,b,c,d,e,f,g,h records and section(header): 0 of suitable view has 3 records and section: 1 had 4 then
Expected result
Section-0
a
b
c
Section-1
d
e
f
g
I'm getting:
Section-0
a
b
c
Section-1
a
b
c
d
The records are being duplicated. I checked the source but source has correct data.
ISSUE:
At the end of each section the source is restarting from the top again to fill the records
My source:
View:
base.DoBind();
var source = new TableSource<string> (Table, ViewModel);
Table.Source = source;
Table.ReloadData();
Table.AlwaysBounceVertical = false;
var set = this.CreateBindingSet<View, ViewModel>();
set.Bind(source).To(vm => vm.CardsList);
set.Apply();
Cell:
protected override void DoBind()
{
var set = this.CreateBindingSet<Cell, ListViewModel>();
set.Bind(LblNum).To(vm => vm.CardNumber);
set.Bind(Balance).To(vm => vm.Balance);
set.Apply();
}
CellViewModel
public class ListViewModel : MvxViewModel
{
private string _CardNumber;
public string Number
{
get { return _Number); }
set { _CardNumber = value; }
}
private string _Balance;
public string Balance
{
get { _Balance; }
set { _Balance = value; }
}
Can anyone please advice how to resolve this
Update
UITableView _tableView;
public TableSource(UITableView tableView, object item) : base(tableView)
{
this.viewModel = item as ViewModel;
this._tableView = tableView;
tableView.RegisterNibForCellReuse(HeaderCell.Nib, HeaderCell.Key); tableView.RegisterNibForCellReuse(UINib.FromName(Cell.Key, NSBundle.MainBundle), Cell.Key);
tableView.RegisterNibForHeaderFooterViewReuse(UINib.FromName(HeaderCell.Key, NSBundle.MainBundle), HeaderCell.Key);
tableView.ReloadData();
var DataDic = new Dictionary<string, List<string>>
{
{ "section1", new List<string> {}},
{ "section2", new List<string> {}},
{ "section3", new List<string> {}}
};
//create the data
var list = new List<TableModel<string>>();
foreach (var section in DataDic)
{
var sectionData = new TableModel<string>()
{
Title = section.Key
};
foreach (var row in section.Value)
{
sectionData.Add(row);
}
list.Add(sectionData);
}
TableItems = list;
}
public override nint NumberOfSections(UITableView tableView)
{
return TableItems.Count;
}
public override nint RowsInSection(UITableView tableview, nint section)
{
int result = 0;
if (section == 0)
{
result = viewModel.NumOfGiftCards;
}
else if (section == 1)
{
result = viewModel.NumOfRewardsCerts;
}
return result;
}
public override nfloat GetHeightForHeader(UITableView tableView, nint section)
{
return section == 2 ? 0f : 74f;
}
public override nfloat GetHeightForRow(UITableView tableView, NSIndexPath indexPath)
{
return indexPath.Section == 2 ? 95f : 62f;
}
public override IEnumerable ItemsSource
{
get
{
return base.ItemsSource;
}
set
{
base.ItemsSource = value;
_tableView.ReloadData();
}
}
public override UIView GetViewForHeader(UITableView tableView, nint section)
{
var header = tableView.DequeueReusableHeaderFooterView(HeaderCell.Key) as HeaderCell;
return header;
}
protected override UITableViewCell GetOrCreateCellFor(UITableView tableView, NSIndexPath indexPath, object item)
{
var cell = tableView.DequeueReusableCell(Cell.Key, indexPath) as Cell;
return cell;
}
public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
viewModel.CardDetailsCommand.Execute(null);
}
I don't think the ItemSource you are binding the CardsList to is not matching up to the TableItems, viewModel.NumOfRewardsCerts or viewModel.NumOfGiftCards that you are using the table source.
Have you had a looked at the MvxExpandableItemSource (the sample is here) It can handle 2 dimensional ItemSources:
private IEnumerable<TItemSource> _itemsSource;
public new IEnumerable<TItemSource> ItemsSource
{
get
{
return _itemsSource;
}
set
{
_itemsSource = value;
_sectionExpandableController.ResetState();
ReloadTableData();
}
}
It deals with expanding and collapsing the from the headers, see below, but you could disable that functionality and force them to be expanded all the time:
Related
I am writing a Xamarin.iOS application with MvvmCross. I am trying to make a table, I can see the items being binded into the source, but I never see any cells being created. The function GetOrCreateCellFor never gets called. Here is my code:
public class ContactsManager
{
ContactsView _contactsView;
public ContactsManager()
{
_contactsView = new ContactsView();
Source = new FriendTableViewSource(_contactsView.FriendsTableView);
_contactsView.FriendsTableView.Source = Source;
}
public FriendTableViewSource Source { get; set; }
}
public class FriendTableViewSource : MvxTableViewSource
{
private readonly List<SeeMyFriendsItemViewModel> _content = new List<SeeMyFriendsItemViewModel>();
private readonly UITableView _tableView;
public FriendTableViewSource(UITableView t) : base(t)
{
_tableView = t;
t.RegisterNibForCellReuse(UINib.FromName(FriendCell.Key, NSBundle.MainBundle), FriendCell.Key);
}
private void Init(IEnumerable<SeeMyFriendsItemViewModel> items)
{
_content.Clear();
_content.AddRange(items);
}
public override System.Collections.IEnumerable ItemsSource
{
get
{
return base.ItemsSource;
}
set
{
// I put a break point here to check if I'm getting the items, and it is, so the binding is fine...
if (value != null)
Init(value.Cast<SeeMyFriendsItemViewModel>());
base.ItemsSource = value;
_tableView.ReloadData();
}
}
public override nfloat GetHeightForRow(UITableView tableView, NSIndexPath indexPath)
{
return 60;
}
protected override UITableViewCell GetOrCreateCellFor(UITableView tableView, NSIndexPath indexPath, object item)
{
// This function never gets called!
return TableView.DequeueReusableCell(FriendCell.Key, indexPath);
}
}
[Register("FriendCell")]
public class FriendCell : MvxTableViewCell
{
public static readonly NSString Key = new NSString("FriendCell");
public static readonly UINib Nib;
static FriendCell()
{
Nib = UINib.FromName("FriendCell", NSBundle.MainBundle);
}
protected FriendCell(IntPtr handle) : base(handle)
{
BackgroundColor = UIColor.Red;
}
}
EDIT
This is what a working version of your source should look like. What's also interesting is that GetOrCreateCellFor won't get called if the table is not added to your view.
public class FriendTableViewSource : MvxTableViewSource
{
private readonly List<SeeMyFriendsItemViewModel> _content = new List<SeeMyFriendsItemViewModel>();
private MvxNotifyCollectionChangedEventSubscription _subscription;
public FriendTableViewSource(UITableView t) : base(t)
{
t.RegisterClassForCellReuse(typeof(FriendCell), FriendCell.Key);
}
private void Init(IEnumerable<SeeMyFriendsItemViewModel> items)
{
_content.Clear();
_content.AddRange(items);
}
public override System.Collections.IEnumerable ItemsSource
{
get
{
return base.ItemsSource;
}
set
{
if (value != null)
{
Init(value.Cast<SeeMyFriendsItemViewModel>());
var collectionChanged = value as System.Collections.Specialized.INotifyCollectionChanged;
if (collectionChanged != null)
{
_subscription = collectionChanged.WeakSubscribe(CollectionChangedOnCollectionChanged);
}
}
base.ItemsSource = value;
ReloadTableData();
}
}
protected override void CollectionChangedOnCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs args)
{
if (args.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
{
foreach (var item in args.NewItems)
{
var chatItem = item as SeeMyFriendsItemViewModel;
_content.Add(chatItem);
}
}
Init(ItemsSource.Cast<SeeMyFriendsItemViewModel>());
base.CollectionChangedOnCollectionChanged(sender, args);
InvokeOnMainThread(() => {
ReloadTableData();
TableView.SetContentOffset(new CGPoint(0, TableView.ContentSize.Height - TableView.Frame.Size.Height), true);
});
}
public override nfloat GetHeightForRow(UITableView tableView, NSIndexPath indexPath)
{
return 60;
}
public override nint RowsInSection(UITableView tableview, nint section)
{
return _content.Count();
}
public override nint NumberOfSections(UITableView tableView)
{
return 1;
}
protected override object GetItemAt(NSIndexPath indexPath)
{
if (indexPath.Row < _content.Count)
return _content[indexPath.Row];
return null;
}
protected override UITableViewCell GetOrCreateCellFor(UITableView tableView, NSIndexPath indexPath, object item)
{
return TableView.DequeueReusableCell(FriendCell.Key, indexPath);
}
}
Override RowsInSection in FriendTableViewSource .
Since tableview needs row count and row height to decide its frame, if height = 0 or count = 0, GetOrCreateCellFor will never be called.
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 want to display an image from a URL to the cell.ImageView.Image variable in UITableView controller's GetCell method. For some reason, the image is displayed only when I click on the cell. It's fetching the image, but the cell is not being updated. The data is an ObservableCollection, so I'm not sure what I am missing. Do I need to call any method explicitly?
public class PasswordGroupsDataSource : UITableViewDataSource
{
const string PlaceholderImagePath = "Placeholder.jpg";
UIImage PlaceholderImage { get; set; }
PasswordsViewController Controller { get; set; }
List<Password> Apps;
public ObservableCollection<PasswordGroup> Groups { get; set; }
public PasswordGroupsDataSource(ObservableCollection<PasswordGroup> groups, PasswordsViewController controller, List<Password> passwords)
{
Controller = controller;
Apps = passwords;
PlaceholderImage = UIImage.FromFile("Images/Placeholder.png");
if (groups == null)
{
throw new ArgumentNullException("groups");
}
Groups = groups;
groups.CollectionChanged += HandleAppsCollectionChanged;
// If either a download fails or the image we download is corrupt, ignore the problem.
TaskScheduler.UnobservedTaskException += delegate(object sender, UnobservedTaskExceptionEventArgs e)
{
e.SetObserved();
};
}
void HandleAppsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
// Whenever the Items change, reload the data.
Controller.TableView.ReloadData();
}
public Password GetPerson(NSIndexPath indexPath)
{
try
{
var personGroup = Groups[indexPath.Section];
return personGroup.People[indexPath.Row];
}
catch (Exception exc)
{
Console.WriteLine("Error in GetPerson: " + exc.Message);
//Occasionally we get an index out of range here
return null;
}
}
public override string TitleForHeader(UITableView tableView, nint section)
{
return Groups[(int)section].Title;
}
public override string[] SectionIndexTitles(UITableView tableView)
{
return Groups.Select(x => x.Title).ToArray();
}
public override nint NumberOfSections(UITableView tableView)
{
return Groups.Count;
}
public override nint RowsInSection(UITableView tableView, nint section)
{
return Groups[(int)section].People.Count;
}
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
var cell = tableView.DequeueReusableCell("P") as PasswordCell;
if (cell == null)
{
cell = new PasswordCell("P");
}
var person = GetPerson(indexPath);
cell.Tag = indexPath.Row;
if (person != null)
{
cell.Person = person;
if (person.Image == null)
{
person.Image = PlaceholderImage;
BeginDownloadingImage(person, indexPath);
}
cell.ImageView.Image = person.Image;
}
return cell;
}
#region Image Support
readonly Dictionary<string, UIImage> images = new Dictionary<string, UIImage>();
readonly List<string> imageDownloadsInProgress = new List<string>();
readonly ImageDownloader imageDownloader = new UIKitImageDownloader();
async void BeginDownloadingImage(Password app, NSIndexPath path)
{
// Queue the image to be downloaded. This task will execute
// as soon as the existing ones have finished.
byte[] data = null;
data = await GetImageData(app.GravatarUrl.ToString());
app.Image = UIImage.LoadFromData(NSData.FromArray(data));
InvokeOnMainThread(() =>
{
if (Apps != null)
{
var cell = Controller.TableView.VisibleCells.Where(c => c.Tag == Apps.IndexOf(app)).FirstOrDefault();
if (cell != null)
cell.ImageView.Image = app.Image;
}
});
}
async Task<byte[]> GetImageData(string ImageUrl)
{
byte[] data = null;
try
{
UIApplication.SharedApplication.NetworkActivityIndicatorVisible = true;
using (var c = new GzipWebClient())
data = await c.DownloadDataTaskAsync(ImageUrl);
}
finally
{
UIApplication.SharedApplication.NetworkActivityIndicatorVisible = false;
}
return data;
}
public override bool CanEditRow(UITableView tableView, NSIndexPath indexPath)
{
return true;
}
public override void CommitEditingStyle(UITableView tableView, UITableViewCellEditingStyle editingStyle, NSIndexPath indexPath)
{
if (editingStyle == UITableViewCellEditingStyle.Delete)
{
Groups.RemoveAt(indexPath.Row);
}
}
#endregion
}
When I debug it, I can see that the image is being set in the BeginDownloadingImage function. What am I missing? Why is the cell not being updated until the cell is clicked?
Note: I was using this from Xamarin Employee Directory Sample.
I am not sure you can do it that way. I would overwrite your placeholder Image on the Person object and then call ReloadRows from your tableview.
InvokeOnMainThread(() =>
{
if (Apps != null)
{
person.Image = app.Image;
Controller.TableView.ReloadRows (new NSIndexPath[]{ path }, UITableViewRowAnimation.Fade);
}
});
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.
Can I create a Sectioned UITableView with MonoTouch.Dialog with alphabetic navigation?
In MonoTouch, I create sectioned UITableViews like so:
public EntityDataSource(UIViewController controller)
{
_controller = controller;
this._entities = repository.GetEntities();
sectionTitles = (from r in _entities
orderby r.StartsWith
select r.StartsWith).Distinct().ToList();
foreach (var entity in _entities)
{
int sectionNumber = sectionTitles.IndexOf(entity.StartsWith);
if (sectionElements.ContainsKey(sectionNumber)) {
sectionElements[sectionNumber].Add(entity);
}
else {
sectionElements.Add(sectionNumber, new List<Entity>() {entity});
}
}
}
public override int NumberOfSections (UITableView tableView)
{
return sectionTitles.Count;
}
public override string TitleForHeader (UITableView tableView, int section)
{
return sectionTitles[section];
}
public override string[] SectionIndexTitles (UITableView tableView)
{
return sectionTitles.ToArray();
}
public override int RowsInSection (UITableView tableview, int section)
{
return sectionElements[section].Count();
}
I want to do this same thing but with MonoTouch.Dialog. Is that possible?
I believe you can only get the index if the style of the UITableView is plain.
In addition, you need to override the method SectionIndexTitles on the UITableViewDataSource, since MonoTouch.Dialog uses its own implementation in the classes SizingSource or Source, what you have to do is create those two subclasses to return the values, and then hook them up by overwriting the DialogViewController.CreateSizingSource () method.
Based on Miguel's answer, here is what I did:
public class EntityViewController : DialogViewController {
DialogViewController parent;
List<string> sectionTitles;
class EntitySource : Source {
EntityViewController parent;
public EntitySource (EntityViewController parent) : base (parent)
{
this.parent = parent;
}
public override string[] SectionIndexTitles (UITableView tableView)
{
return parent.sectionTitles.ToArray();
}
}
class SizingIndexedSource : Source {
EntityViewController parent;
public SizingIndexedSource (EntityViewController parent) : base (parent)
{
this.parent = parent;
}
public override string[] SectionIndexTitles (UITableView tableView)
{
return parent.sectionTitles.ToArray();
}
}
public override Source CreateSizingSource (bool unevenRows)
{
if (unevenRows)
return new SizingIndexedSource (this);
else
return new EntitySource (this);;
}
private RootElement GetEntities() {
EntityRepository db = new EntityRepository();
List<Entity> _entities = db.GetEntities();
sectionTitles = (from r in _entities
orderby r.StartsWith
select r.StartsWith).Distinct().ToList();
var root = new RootElement ("Entities") ;
foreach (var item in sectionTitles) {
var section = new Section(item,String.Empty);
foreach (var entity in _entities.Where(e => e.StartsWith == item)) {
section.Add(new StringElement(entity.FirstName + " " + entity.LastName, "Title"));
}
root.Add(section);
}
return root;
}
public EntityViewController (DialogViewController parent) : base (UITableViewStyle.Grouped, null)
{
this.parent = parent;
Root = GetEntities();
this.Style = UITableViewStyle.Plain;
this.EnableSearch = true;
this.SearchPlaceholder = "Find a contact";
this.AutoHideSearch = true;
}
}