Using Miguel de Icaza's Patterns for Creating UITableViewCells, I have created a custom UITableViewCell and turned that into a MonoTouch.Dialog Element. I'm using the elements API to create an edit form, using a few of my custom elements.
I'm trying to figure out how to respond to the deletion of the element. My custom element has a reference to the record it represents in the database. I want to respond to a deleted event in the same way I would respond to a Selected event, where I get the DialogViewController, UITableView, and NSIndexPath. Assuming such an event existed for an Element that I can respond to, I would fire a delete statement to the database with the given record id.
Based on Miguel's answer, I added a public Delete method to the sub classed Element called MyDataElement.
public class MyDataElement : Element {
static NSString key = new NSString ("myDataElement");
public MyData MyData;
public MyDataElement (MyData myData) : base (null)
{
MyData = myData;
}
public override UITableViewCell GetCell (UITableView tv)
{
var cell = tv.DequeueReusableCell (key) as MyDataCell;
if (cell == null)
cell = new MyDataCell (MyData, key);
else
cell.UpdateCell (MyData);
return cell;
}
public void Delete() {
Console.WriteLine(String.Format("Deleting record {0}", MyData.Id));
}
}
Then over on my sub classed DialogViewController, I handle the CommitEditingStyle method, cast the element as MyDataElement, then call the Delete method:
public class EntityEditingSource : DialogViewController.Source {
public EntityEditingSource(DialogViewController dvc) : base (dvc) {}
public override bool CanEditRow (UITableView tableView, NSIndexPath indexPath)
{
// Trivial implementation: we let all rows be editable, regardless of section or row
return true;
}
public override UITableViewCellEditingStyle EditingStyleForRow (UITableView tableView, NSIndexPath indexPath)
{
// trivial implementation: show a delete button always
return UITableViewCellEditingStyle.Delete;
}
public override void CommitEditingStyle (UITableView tableView, UITableViewCellEditingStyle editingStyle, NSIndexPath indexPath)
{
// In this method, we need to actually carry out the request
var section = Container.Root [indexPath.Section];
var element = section [indexPath.Row];
//Call the delete method on MyDataElement
(element as MyDataElement).Delete();
section.Remove (element);
}
}
You would have to modify the source to handle the delete event in the Source class and dispatch that message to the Element, in the same way that it is done for the other events.
Related
How to add Section headers in UICollectionView in Xamarin.iOS and MVVMCross.
I just want to ask the best approach. I am searching from 2 days but unable to find any simple approach. My data is List and and Section Contain List
My design looks like
To add supplementary views within a UICollectionView, you'll need to override the CollectionViewSource to provide them.
The base code for this in MvvmCross is in https://github.com/MvvmCross/MvvmCross/blob/3.5/Cirrious/Cirrious.MvvmCross.Binding.Touch/Views/MvxCollectionViewSource.cs and https://github.com/MvvmCross/MvvmCross/blob/3.5/Cirrious/Cirrious.MvvmCross.Binding.Touch/Views/MvxBaseCollectionViewSource.cs
A good Xamarin tutorial for CollectionViews is http://developer.xamarin.com/guides/ios/user_interface/introduction_to_collection_views/
If you want to make the supplementary view bindable then you can do these by adapting the supplementary views in a similar way to the cells - e.g. copying and pasting the BindingContext`DataContext` code from https://github.com/MvvmCross/MvvmCross/blob/3.5/Cirrious/Cirrious.MvvmCross.Binding.Touch/Views/MvxCollectionViewCell.cs and then ensuring you set the DataContext when the supplementary cell is used or reused within the collection view source.
There is an open issue requesting this functionality within MvvmCross or a sample - https://github.com/MvvmCross/MvvmCross/issues/339 - but no-one (except me!) has ever commented on it... would be happy to see it added.
A bit late for the party, but here you have my working code for:
Using several sections in a collection
Use a header for each section
Change the data at your convenience:
public class SearchCollectionViewSource : MvxCollectionViewSource
{
private List<SearchResult> results { get { return ItemsSource as List<SearchResult>; } }
public SearchCollectionViewSource (UICollectionView collectionView) : base(collectionView) { }
public SearchCollectionViewSource (UICollectionView collectionView, NSString defaultCellIdentifier) : base(collectionView, defaultCellIdentifier) { }
public override UICollectionReusableView GetViewForSupplementaryElement (UICollectionView collectionView, NSString elementKind, NSIndexPath indexPath)
{
return (HeaderView)collectionView.DequeueReusableSupplementaryView(elementKind, HeaderView.Key, indexPath);
}
public override nint NumberOfSections (UICollectionView collectionView)
{
return results.Count;
}
public override nint GetItemsCount (UICollectionView collectionView, nint section)
{
return results[(int)section].photos.Count;
}
protected override object GetItemAt(NSIndexPath indexPath)
{
return results [indexPath.Section].photos [indexPath.Row];
}
}
public sealed class HeaderView : UICollectionReusableView
{
public static string Key = "HeaderId";
[Export("initWithFrame:")]
public HeaderView(System.Drawing.RectangleF frame)
: base(frame)
{
UIView separator = new UIView() { Frame = new System.Drawing.RectangleF(0, 0, (float)UIScreen.MainScreen.Bounds.Width, 10), BackgroundColor = UIColor.LightGray };
AddSubview(separator);
}
}
So I have a UITableView where I want to push to a details controller when the row is selected.
My attempt was to:
public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
var controller = new BlogDetailViewController();
navController.PushViewController(controller, true);
tableView.DeselectRow (indexPath, true);
}
But I am getting the complaint that BlogDetailViewController() takes an argument.
My BlogDetailViewController:
public partial class BlogDetailViewController : UIViewController
{
public string blogTitle;
public BlogDetailViewController (IntPtr handle) : base (handle)
{
}
}
What is Intptr handle and how do I pass it in? I tried adding a zero argument constructor and pushing to that, but when I ran the app it pushed to a black screen.
If you're instantiating it from a XIB, I believe you want to use
UIStoryboard board = UIStoryboard.FromName ("name", null);
UIViewController ctrl = (UIViewController)board.InstantiateViewController ("name");
UIApplication.SharedApplication.KeyWindow.RootViewController = view;
add this line also in last
i wan't to use UITableView.AllowsMultipleSelectionDuringEditing with Monotouch.Dialog. If the property is set to true, the click on the table (with edit mode enabled) seems to be ignored (no selection happens). If there is an Element.Tapped, it will be executed. In my current implementation it will push a new UIView to the NavigationController, but this is not what you expect in edit-mode.
You can reproduce the behaviour with the monotouch.dialog-sample project, just change the EditingDialog Constructor (DemoEditing.cs:57) to the following:
public EditingDialog (RootElement root, bool pushing) : base (root, pushing)
{
TableView.AllowsMultipleSelectionDuringEditing = true;
}
Is there a way to use AllowsMultipleSelectionDuringEditing? If yes, what's wrong with my approach?
I just had the same problem with my own code. The problem is that some of the MonoTouch.Dialog elements have their cell SelectionStyle set to UITableViewCellSelectionStyle.None.
I solved it by sub-classing Source or SizingSource:
public class MyTableViewSource : Source
{
public MyTableViewSource(DialogViewController container) : base(container)
{
}
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
var cell = base.GetCell(tableView, indexPath);
cell.SelectionStyle = UITableViewCellSelectionStyle.Gray; // something other than None
return cell;
}
}
Then in your DialogViewController:
public class MyDialogController : DialogViewController
{
public override void ViewDidLoad()
{
base.ViewDidLoad();
// setup root element
Root = new RootElement();
// . . .
TableView.Source = new MyTableViewSource(this);
TableView.AllowsMultipleSelectionDuringEditing = true;
}
}
Using Monotouch 5.2.11 iOS
I have followed this tutorial (http://tirania.org/monomac/archive/2011/Jan-18.html), created a custom cell with an image and have also added the IElementSizing Interface. The GetHeight is never called.
Similar questions have been asked and the generally accepted solution was to make sure and create the RootElements first, set the UnEvenRows=true before adding them to the Controller. This did not work. I've tried that as well as about every other combination of adding sections to root elements and have not ever seen the GetHeight fired.
The MyDataElement is an image that is 320x200 which displays fine, but the string element that comes after it is not shown (assuming it is behind it). Consequently if I drag the custom cell up above the top, it disappears, reappears, and the second stringelement displays on top of it.
Here is the code I've tried:
public class MyDataElement : Element, IElementSizing {
static NSString key = new NSString ("myDataElement");
public MyData MyData;
public MyDataElement (MyData myData) : base (null)
{
MyData = myData;
}
public float GetHeight (UITableView tableView, NSIndexPath indexPath){
return 200f; // break point here is never hit ever
}
public override UITableViewCell GetCell (UITableView tv)
{
var cell = tv.DequeueReusableCell (key) as MyDataCell;
if (cell == null)
cell = new MyDataCell (MyData, key);
else
cell.UpdateCell (MyData);
return cell;
}
public partial class TableTester : DialogViewController
{
public TableTester () : base (UITableViewStyle.Grouped, null)
{
var re = new RootElement("Sample") {
new Section("Testy") {
new MyDataElement(new MyData() { stuff="hello"}),
new StringElement("Sample")
}
};
re.UnevenRows = true;
this.Root = re;
//this.Root = root;
}
}
In addition to that I've even done this which didn't work either:
public class TestNavigator : UINavigationController {
public TestNavigator() {
TabBarItem = new UITabBarItem("Test", null, 1);
var re = new RootElement("Sample") {
new Section("Sammy") {
new StringElement("Sample"),
new MyDataElement(new MyData() { stuff="sam"}),
new StringElement("Sample 2")
}
};
re.UnevenRows = true;
var dv = new DialogViewController(re);
re.UnevenRows = true;
PushViewController(dv, true);
}
After plenty of trial and error, I had to make sure and remove the reference to Monotouch.Dialog that I had downloaded from github and use the built in reference. It seems that the getheight maybe broken in github.
My problem is as follows:
I am creating a section with a number of ImageStringElements that when selected an audio file will play, e.g.
Section s = new Section();
foreach (var idea in ideas)
{
s.Add(new ImageStringElement(idea.Id, delegate {ElementTapped();}, playImage));
}
Now when one of the elements is tapped, I would like to change the playImage to another one, i.e. PauseImage. Then again, when is it selected it changes back to the PlayImage. Not sure how to do this in the ElementTapped() method. Basically I would like to have a similar functionality as in the voice memos app.
You can subclass ImageStringElement and make two changes:
Add:
class FlippingImageElement : ImageStringElement
{
UIImage currentImage;
UITableViewCell currentCell;
public FlippingImageElement (string caption, UIImage image) : base (caption, image)
{
currentImage = image;
}
public override UITableViewCell GetCell (UITableView tv)
{
var cell = base.GetCell (tv);
cell.ImageView.Image = currentImage;
currentCell = cell;
}
public void SetImage (UIImage image)
{
currentImage = image;
if (currentCell != null)
currentCell.ImageView.Image = currentImage;
}
}
Use this new element instead of the MonoTouch.Dialog one, and call the SetImage API to change the image