dynamically change image in ImageStringElement as part of monotouch.dialog - xamarin.ios

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

Related

MonoTouch DialogViewController - why must it be in the first place of a UINavigationController?

I want to use a DialogViewController inside of a UITabViewController.
Problem: Nested elements don't show a navigation bar, and so it is not possible to go back.
When I push my class (inherited from DialogViewController) to a UINavigationController, then the behavior is correct. If I use the same class in a tab of a UITabViewController (even with an underlying UINavigationController), then the behaviour is wrong.
Can anyone help me out?
Although the question is not assisted with some code sample, I made a small example hoping to solve your question. For this example I used the Tabbed Application template which comes with Xamarin.iOS and named it TabbingTest.
The following code goes in the AppDelegate. Change the FinishedLaunching method to contain:
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
window = new UIWindow (UIScreen.MainScreen.Bounds);
var viewControllers = new UIViewController[]
{
CreateTabFor("Test", "first", new TestDialogController ()),
CreateTabFor("Second", "second", new SecondViewController ()),
};
tabBarController = new UITabBarController ();
tabBarController.ViewControllers = viewControllers;
tabBarController.SelectedViewController = tabBarController.ViewControllers[0];
window.RootViewController = tabBarController;
window.MakeKeyAndVisible ();
return true;
}
Then add the following methods:
private int _createdSoFarCount = 0;
private UIViewController CreateTabFor(string title, string imageName, UIViewController view)
{
var controller = new UINavigationController();
controller.NavigationBar.TintColor = UIColor.Black;
var screen = view;
SetTitleAndTabBarItem(screen, title, imageName);
controller.PushViewController(screen, false);
return controller;
}
private void SetTitleAndTabBarItem(UIViewController screen, string title, string imageName)
{
screen.Title = NSBundle.MainBundle.LocalizedString (title, title);
screen.TabBarItem = new UITabBarItem(title, UIImage.FromBundle(imageName),
_createdSoFarCount);
_createdSoFarCount++;
}
Create a class named TestDialogController and paste the following code inside.
using System;
using MonoTouch.Dialog;
using MonoTouch.UIKit;
namespace TabbingTest
{
public class TestDialogController : DialogViewController
{
public TestDialogController (): base(UITableViewStyle.Plain,null,false)
{
var root = new RootElement ("Tabbing test"){
new Section (){
new RootElement ("First level", 0, 0) {
new Section (null, "This is the first level."){
new RootElement ("Second level", 0, 0) {
new Section (null, "This is the second level."){
new BooleanElement ("Flipflops", false)
}
}
}
}}
};
this.Root = root;
}
}
}
Now run the application.
You can see that even the nested elements show up nicely in the navigation bar. Even with multilevel nesting.

push a view controller from selecting a row in a table view

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

Monotouch Dialog Custom Element and GetHeight not being called

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.

Monotouch Dialog Datepicker and RadioGroup Navigationitem

I can´t figure out how to correctly design the pushed viewcontrollers navigation back item of a RadioGroup.
So in the follow up screen where the languages are selectable the back Button says "Settings" and is blue. But I want to make it say back and change its design which mechanisms exists and I´m already using in other screens.
I build it up like this:
var rootSettings = new RootElement ("Settings");
var sectionNotificationSettings = new Section ("Notification settings");
BooleanElement pushEnabled = new BooleanElement("Push notifications", settings.PushEnabled);
sectionNotificationSettings.Add(pushEnabled);
var sectionCountrySettings = new Section("Country settings");
var rootRadioGroup = new TransparentRootElement ("Language", new RadioGroup("languages", 0));
var sectionRadioElements = new Section("");
foreach(var language in settings.Languages)
{
RadioElement selectableLanguage = new RadioElement(language.Key, "languages");
sectionRadioElements.Add(selectableLanguage);
}
rootRadioGroup.Add(sectionRadioElements);
sectionCountrySettings.Add(rootRadioGroup);
rootSettings.Add (sectionNotificationSettings);
rootSettings.Add(sectionCountrySettings);
And here I define the TransparentRootElement where I thought I can edit the navigation Item:
public class TransparentRootElement : RootElement {
public TransparentRootElement (string caption) : base (caption)
{
}
public TransparentRootElement (string caption, Group radioGroup ) : base (caption, radioGroup)
{
}
public override void Selected (DialogViewController dvc, UITableView tableView, NSIndexPath path)
{
base.Selected (dvc, tableView, path, true);
}
void HandleMenuButtonTouchUpInside (object sender, EventArgs e)
{
_dvc.NavigationController.PopViewControllerAnimated(true);
}
public override UITableViewCell GetCell (UITableView tv)
{
var cell = base.GetCell (tv);
//cell.BackgroundColor = UIColor.White;
return cell;
}
}
I tried many edit approaches but none of the worked. I also began editing the Elements.cs in Monotouch Dialog but this also did not helped me alot.
Anyone who has a suggestion?
Thank you very much!
I believe to change the navigation's back button, you have to hide the default back button and then assign your own. (Right before you push the new view controller, I believe in your case, it would be before you push the Language screen) Something like this:
toPushscreen.NavigationItem.SetHidesBackButton(true, true);
toPushscreen.NavigationItem.LeftBarButtonItem = new UIBarButtonItem("Back", UIBarButtonItemStyle.Plain, myHandler);
currentScreen.NavigationController.PushViewController(toPushscreen, true);
Hope this helps!

MonoTouch.Dialog : Element Delete Event

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.

Resources