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.
Related
EDIT 2: If you're looking for an answer to a similar problem, check Stuart's answer and my comments on it.
EDIT: I am actually getting a Mono.Debugger.Soft.VMDisconnectedException. I also recently installed Windows 8.1 and Resharper (though Resharper is suspended now).
When I access a very simple list property of my view model in my MVVMCross Xamarin iOS application, the program fails. It doesn't quit most of the time: it acts like it's running. The simulator has a black screen and there is no exception. If I breakpoint on if (messagesViewModel != null) source.ItemsSource = messagesViewModel.Messages; and then type messagesViewModel.Messages into the Immediate Window, everything stops, so I can tell it is failing at this line. If instead I "step over", it never moves to the next line.
I was having similar behavior when I was toggling this code in the MvxTableViewSource:
public override int RowsInSection(UITableView tableview, int section)
{
return 1;
}
My view model looks like this:
public class MessagesViewModel : MvxViewModel
{
private List<BaseMessage> _messages = null;
public List<BaseMessage> Messages
{
get
{
return _messages; //yes, I know I'm returning null
//I wasn't at first.
}
}
public MessagesViewModel()
{
}
}
This is my ViewDIdLoad on the MvxTableViewController:
public override void ViewDidLoad()
{
base.ViewDidLoad();
var source = new MessagesTableViewSource(TableView);
//was binding here, removed it for debug purposes
//failure on second line here
var messagesViewModel = ViewModel as MessagesViewModel;
if (messagesViewModel != null) source.ItemsSource = messagesViewModel.Messages;
TableView.Source = source;
TableView.ReloadData();
}
Some initialization code:
public class App : MvxApplication
{
public App()
{
var appStart = new MvxAppStart<MessagesViewModel>();
Mvx.RegisterSingleton<IMvxAppStart>(appStart);
}
}
public partial class AppDelegate : MvxApplicationDelegate
{
//empty functions removed.
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
Window = new UIWindow(UIScreen.MainScreen.Bounds);
var presenter = new MvxTouchViewPresenter(this, Window);
var setup = new Setup(this, presenter);
setup.Initialize();
var startup = Mvx.Resolve<IMvxAppStart>();
startup.Start();
Window.MakeKeyAndVisible();
return true;
}
}
I suspect whatever the error is, it isn't in any of the code you have posted.
I just created a simple ViewModel:
public class FirstViewModel
: MvxViewModel
{
private List<string> _items = new List<string>() { "One", "Two", "Three"};
public List<string> Items
{
get { return _items; }
set { _items = value; RaisePropertyChanged(() => Items); }
}
}
And a simple View:
[Register("FirstView")]
public class FirstView : MvxTableViewController
{
public override void ViewDidLoad()
{
base.ViewDidLoad();
// ios7 layout
if (RespondsToSelector(new Selector("edgesForExtendedLayout")))
EdgesForExtendedLayout = UIRectEdge.None;
var firstViewModel = ViewModel as FirstViewModel;
var source = new MessagesTableViewSource(TableView);
source.ItemsSource = firstViewModel.Items;
TableView.Source = source;
}
public class MessagesTableViewSource : MvxTableViewSource
{
public MessagesTableViewSource(UITableView tableView) : base(tableView)
{
tableView.RegisterClassForCellReuse(typeof(MessagesCell), new NSString("MessagesCell"));
}
protected override UITableViewCell GetOrCreateCellFor(UITableView tableView, NSIndexPath indexPath, object item)
{
return tableView.DequeueReusableCell("MessagesCell");
}
}
public class MessagesCell : MvxTableViewCell
{
public MessagesCell(IntPtr handle)
: base(handle)
{
var txt = new UILabel(new RectangleF(0, 0, 320, 44));
Add(txt);
this.DelayBind(() =>
{
this.CreateBinding(txt).Apply();
});
}
}
}
And this code runs fine...
I wouldn't completely trust the integration of Xamarin.iOS with the Immediate window - it is better now than it used to be, but I've seen several problems with it before.
Some things to possibly check:
does the above code work for you?
if it does, then what's in your BaseMessage and MessagesTableViewSource classes - perhaps they are causing the problem?
can you use Mvx.Trace("The list is {0}", messagesViewModel.Messages ?? "-null") to view the list? Can you use trace within the ViewModel property get - is it being called? Can you use trace within the ViewModel constructor?
are all your assemblies building against the same versions of things? Are all your assemblies definitely rebuilt? (Check "Build|Configuration Manager")- what version of Xamarin.iOS are you running in VS and in the Mac?
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.
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;
}
}
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!
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