I want to show a UIPopoverController by clicking on a UIBarButtonItem on the Navigation bar. This UIPopoverController needs a "ContentViewController", that would be a MvxTableViewController with some data-binding. The problem is, if I instantiate some class derived from MvxTableViewController directly - instead of doing ShowViewModel<blah>(), I got an exception on "base.ViewDidLoad" on the overriden method ViewDidLoad.
What am I missing?
Thanks in advance!
EDIT:
If i use, for instance, a MvxViewController with an UITableView:
public class Test : MvxViewController
{
public override void ViewDidLoad()
{
View = new UIView() { BackgroundColor = UIColor.White };
//TableView = new UITableView(new RectangleF(0, 0, 300, 300));
base.ViewDidLoad();
var table = new UITableView(new RectangleF(0, 0, 300, 300));
// ios7 layout
if (RespondsToSelector(new Selector("edgesForExtendedLayout")))
EdgesForExtendedLayout = UIRectEdge.None;
var source = new MvxStandardTableViewSource(table, "TitleText Nome");
table.Source = source;
var set = this.CreateBindingSet<Test, Core.ViewModels.FirstViewModel>();
set.Bind(source).To(vm => vm.Distritos);
set.Apply();
table.ReloadData();
}
}
And if i have, on FirstViewModel's ViewDidLoad, during the construction of a Navigation Bar:
var buttonLocalizacao = new UIBarButtonItem("Localização", UIBarButtonItemStyle.Plain, (s, e) => {
distritoViewController = new Test();
nc = new UINavigationController(distritoViewController);
var distritoPopOver = new UIPopoverController(nc);
distritoPopOver.ContentViewController = nc;
distritoPopOver.PopoverContentSize = new SizeF(300, 300);
distritoPopOver.PresentFromBarButtonItem((UIBarButtonItem)s, UIPopoverArrowDirection.Up, true);
});
Everytime i hit the UIBarButtonItem "Localização" i get an exception on Test's "base.ViewDidLoad". Does this make sense?
EDIT 2:
This is the exception i receive:
"Unhandled Exception:
System.NullReferenceException: Object reference not set to an instance of an object
at Cirrious.MvvmCross.ViewModels.MvxViewModelLoader.LoadViewModel (Cirrious.MvvmCross.ViewModels.MvxViewModelRequest request, IMvxBundle savedState) [0x00000] in :0
at Cirrious.MvvmCross.Touch.Views.MvxViewControllerExtensionMethods.LoadViewModel (IMvxTouchView touchView) [0x00000] in :0
at Cirrious.MvvmCross.Touch.Views.MvxViewControllerExtensionMethods+<>c__DisplayClass1.b__0 () [0x00000] in :0
at Cirrious.MvvmCross.Views.MvxViewExtensionMethods.OnViewCreate (IMvxView view, System.Func`1 viewModelLoader) [0x00000] in :0
at Cirrious.MvvmCross.Touch.Views.MvxViewControllerExtensionMethods.OnViewCreate (IMvxTouchView touchView) [0x00000] in :0
at Cirrious.MvvmCross.Touch.Views.MvxViewControllerAdapter.HandleViewDidLoadCalled (System.Object sender, System.EventArgs e) [0x00000] in :0 "
Finally got it:
Instead of:
var buttonLocalizacao = new UIBarButtonItem("Localização", UIBarButtonItemStyle.Plain, (s, e) => {
distritoViewController = new Test();
nc = new UINavigationController(distritoViewController);
var distritoPopOver = new UIPopoverController(nc);
distritoPopOver.ContentViewController = nc;
distritoPopOver.PopoverContentSize = new SizeF(300, 300);
distritoPopOver.PresentFromBarButtonItem((UIBarButtonItem)s, UIPopoverArrowDirection.Up, true);
});
I had to create a distinct ViewModel to hold my MvxTableViewController (each MvxTableViewController, or MvxViewController, demands a corresponding ViewModel?), meaning, i could not bind "Test", that is a MvxTableViewController, to another, different, ViewModel (FirstViewModel for instance). "Test" must have a ViewModel of it's own.
So, eventually the corresponding ViewModel must be instantiated previously, and only after that can we instantiate the MvxTableViewController using "CreateViewControllerFor". Replacing the above "Test" for "DistritoViewModel", the rest is straightforward:
var buttonLocalizacao = new UIBarButtonItem("Localização", UIBarButtonItemStyle.Plain, (s, e) => {
if (distritoPopOver == null)
{
var viewModel = new DistritoViewModel();
var secondv = this.CreateViewControllerFor(viewModel) as MvxTableViewController;
nc = new UINavigationController(secondv);
distritoPopOver = new UIPopoverController(nc);
distritoPopOver.PopoverContentSize = new SizeF(300, 300);
}
distritoPopOver.PresentFromBarButtonItem((UIBarButtonItem)s, UIPopoverArrowDirection.Up, true);
});
Keep in mind: the variable distritoPopover, that holds the UIPopoverController, must be a class variable, or instantiated outside the Action in UIBarButtonItem, otherwise it will be garbage collected and cause an immediate crash after display!
Thanks everyone for the tips :)
Related
I have a UIPageViewController in which I've implemented a caching mechanism. Practically I have a pool of view controllers that I try to reuse as much as possible when the next or previous view controller is requested in the UIPageViewControllerDataSource. So when the data source requests the previous or the next page I first check if that page has already been shown and return the appropriate view controller.
It all works fine with the default swipe gesture, and the internal method to change page. Now I need to disable the swipe gesture, so I'm not setting the data source, and instead, I have two buttons to go to the previous and next page, and using setViewControllers(_:direction:animated:completion:) to change page programmatically. It works fine when going always in the same direction, but as soon as I change it, and so I'm using a cached view controller, it shows a blank page.
The code is exactly the same as before, if not for setting the view controller programmatically. I've tried both with or without animation and the result is the same and if I remove caching it also works well. My question is, am I forgetting something? Is the UIPageViewController doing something internally that I'm not doing when the data source is assigned?
EDIT
Here's a simplified version of the code. It's a Xamarin Project, but I suppose it's understandable
public class MyPageViewController : AbstractPageViewController
{
const int CacheCapacity = 5;
public int initialItemId { get; set; }
public List<int> ItemIds { get; set; }
readonly List<ChildViewController> viewControllerCache = new List<ChildViewController>(CacheCapacity + 1);
public override void ViewDidLoad()
{
base.ViewDidLoad();
DataSource = null;
var vc = GetDocumentViewController(initialItemId);
SetViewControllers(new[] { vc }, UIPageViewControllerNavigationDirection.Forward, false, null);
var nextButtonItem = new UIBarButtonItem
{
Enabled = true
};
var previousButtonItem = new UIBarButtonItem
{
Enabled = true
};
nextButtonItem.Clicked += NextDocumentButton_Clicked;
previousButtonItem.Clicked += PreviousDocumentButton_Clicked;
var rightButtons = new UIBarButtonItem[2];
rightButtons[0] = nextButtonItem;
rightButtons[1] = previousButtonItem;
NavigationItem.SetRightBarButtonItems(rightButtons, false);
}
private void PreviousDocumentButton_Clicked(object sender, EventArgs e)
{
var referenceVc = (ChildViewController)ViewControllers.FirstOrDefault();
var referenceId = referenceVc.ItemId;
var index = ItemIds.FindIndex(dp => dp.Id == referenceId);
if (index < 1)
return;
var previousDocumentId = ItemIds[index - 1];
var vc = GetDocumentViewController(previousDocumentId);
SetViewControllers(new[] { vc }, UIPageViewControllerNavigationDirection.Reverse, false, null);
}
private void NextDocumentButton_Clicked(object sender, EventArgs e)
{
var referenceVc = (ChildViewController)ViewControllers.FirstOrDefault();
var referenceId = referenceVc.ItemId;
var index = ItemIds.FindIndex(dp => dp.Id == referenceId);
if (index < 0 || index >= ItemIds.Count)
return;
var nextDocumentId = ItemIds[index + 1];
var vc = GetDocumentViewController(nextDocumentId);
SetViewControllers(new[] { vc }, UIPageViewControllerNavigationDirection.Forward, false, null);
}
ChildViewController GetDocumentViewController(int ItemId)
{
var cachedViewController = viewControllerCache.FirstOrDefault(dvc => dvc.ItemId == ItemId);
if (cachedViewController != null)
return cachedViewController;
var vc = new ChildViewController();
vc.SetData(itemId);
viewControllerCache.Add(vc);
if (viewControllerCache.Count > CacheCapacity)
{
viewControllerCache[0].RecycleIfNeeded();
viewControllerCache.RemoveAt(0);
}
return vc;
}
}
It turned out that it was due to a recycling mechanism that was implemented in my code.
In particular, there's a forced recycling of the content of the view controller on ViewDidDisappear. I've disabled it in this case and then it works as it should. This also means that when the UIPageViewController has a data source, and is managing the child view controller directly, ViewDidDisappear is not called when changing page through swiping.
Hopefully someone can help me with the following, because I am completely stuck.
I receive the exception below in my MvvmCross Xamarin.iOS application when I bind on my TableView. This only happens when I change the datasource (each time I change the date, the TableView needs to get updated).
Incident Identifier: 7E7C2B15-7CC4-4AE7-9891-C4FD82358009
CrashReporter Key: 46CC21C0-DDE1-4313-9658-EC79D767939B
Hardware Model: iPhone7,2
Process: UurwerkiOS [4326]
Path: /var/containers/Bundle/Application/75969477-A516-44C3-A5A3-5B24DDDC89C8/UurwerkiOS.app/UurwerkiOS
Identifier: com.route2it.uurwerk
Version: 1.0 (1.0.96)
Code Type: ARM-64
Parent Process: ??? [1]
Date/Time: 2016-07-04T13:16:38Z
Launch Time: 2016-07-04T13:16:31Z
OS Version: iPhone OS 9.3.2 (13F69)
Report Version: 104
Exception Type: SIGABRT
Exception Codes: #0 at 0x1816ac11c
Crashed Thread: 5
Application Specific Information:
*** Terminating app due to uncaught exception 'System.AggregateException', reason: 'System.AggregateException: A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread. ---> System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
at System.ThrowHelper.ThrowInvalidOperationException (ExceptionResource resource) <0x10044bec0 + 0x00024> in <filename unknown>:0
at System.Collections.Generic.List`1+Enumerator[T].MoveNextRare () <0x1003bf900 + 0x0002f> in <filename unknown>:0
at System.Collections.Generic.List`1+Enumerator[T].MoveNext () <0x1003bf830 + 0x0009f> in <filename unknown>:0
at MvvmCross.Binding.BindingContext.MvxTaskBasedBindingContext.<OnDataContextChange>b__20_0 () <0x1007c1990 + 0x0023f> in <filename unknown>:0
at System.Threading.Tasks.Task.InnerInvoke () <0x10043f1f0 + 0x0005f> in <filename unknown>:0
at System.Threading.Tasks.Task.Execute () <0x10043ea20 + 0x00043> in <filename unknown>:0
--- End of inner exception stack trace ---
---> (Inner Exception #0) System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
at System.ThrowHelper.ThrowInvalidOperationException (ExceptionResource resource) <0x10044bec0 + 0x00024> in <filename unknown>:0
at System.Collections.Generic.List`1+Enumerator[T].MoveNextRare () <0x1003bf900 + 0x0002f> in <filename unknown>:0
at System.Collections.Generic.List`1+Enumerator[T].MoveNext () <0x1003bf830 + 0x0009f> in <filename unknown>:0
at MvvmCross.Binding.BindingContext.MvxTaskBasedBindingContext.<OnDataContextChange>b__20_0 () <0x1007c1990 + 0x0023f> in <filename unknown>:0
at System.Threading.Tasks.Task.InnerInvoke () <0x10043f1f0 + 0x0005f> in <filename unknown>:0
at System.Threading.Tasks.Task.Execute () <0x10043ea20 + 0x00043> in <filename unknown>:0
At first I thought it was related to one of my Async methods (which maybe not complete in time while the next one was already running). So I removed all my async code, but the exception still occurs. I also made sure I don't change the enumerable collection myself. I fetch the data (which is simply a in memory array) and return it as a new list to the property to which the TableView is bound. Below are the code snippets that make up the binding (it's a lot of information but I wanted to be as complete as possible):
CalendarViewController:
public override void ViewDidLoad()
{
base.ViewDidLoad();
if (NavigationController != null)
NavigationController.NavigationBarHidden = false;
InitCalendar();
InitNavigationItem();
InitTableView();
ApplyConstraints();
var shiftForDateTableViewSource = new MvxSimpleTableViewSource(_tableView, CalendarTableViewCell.Key, CalendarTableViewCell.Key);
shiftForDateTableViewSource.DeselectAutomatically = true;
_tableView.RowHeight = 45;
_tableView.Source = shiftForDateTableViewSource;
var set = this.CreateBindingSet<CalendarView, CalendarViewModel>();
set.Bind(shiftForDateTableViewSource).To(vm => vm.ShiftsForSelectedDate);
set.Bind(shiftForDateTableViewSource).For(vm => vm.SelectionChangedCommand).To(vm => vm.ShiftSelectedCommand);
set.Apply();
_tableView.ReloadData();
}
private void InitTableView()
{
_tableView = new UITableView();
_tableView.RegisterClassForCellReuse(typeof(UITableViewCell), CalendarTableViewCell.Key);
Add(_tableView);
}
CalendarTableViewCell:
public partial class CalendarTableViewCell : MvxTableViewCell
{
public static readonly NSString Key = new NSString("CalendarTableViewCell");
public static readonly UINib Nib;
static CalendarTableViewCell()
{
Nib = UINib.FromName("CalendarTableViewCell", NSBundle.MainBundle);
}
protected CalendarTableViewCell(IntPtr handle) : base(handle)
{
}
public override void LayoutSubviews()
{
base.LayoutSubviews();
var set = this.CreateBindingSet<CalendarTableViewCell, Shift>();
set.Bind(StartTimeLabel).To(vm => vm.StartDate).WithConversion("StringFormat", "HH:mm");
set.Bind(EndTimeLabel).To(vm => vm.EndDate).WithConversion("StringFormat", "HH:mm");
set.Bind(ColorBarView).For("BackgroundColor").To(vm => vm.Color).WithConversion("RGB");
set.Bind(TitleLabel).To(vm => vm).WithConversion("ConcatenatedEventTitle");
set.Bind(LocationLabel).To(vm => vm.Location);
set.Apply();
}
}
CalendarViewModel:
public class CalendarViewModel
: MvxViewModel
{
private readonly IShiftService _shiftService;
public CalendarViewModel(IShiftService shiftService)
{
if (shiftService == null)
throw new ArgumentNullException(nameof(shiftService));
_shiftService = shiftService;
}
public override void Start()
{
base.Start();
Shifts = _shiftService.GetShiftsForEmployeeAsync(1);
}
private IEnumerable<Shift> _shifts;
public IEnumerable<Shift> Shifts
{
get { return _shifts; }
set
{
SetProperty(ref _shifts,
value,
nameof(Shifts));
}
}
private IEnumerable<Shift> _shiftsForSelectedDate;
public IEnumerable<Shift> ShiftsForSelectedDate
{
get { return _shiftsForSelectedDate; }
private set
{
if (_shiftsForSelectedDate == value)
return;
SetProperty(ref _shiftsForSelectedDate,
value,
nameof(ShiftsForSelectedDate));
}
}
private DateTime? _selectedDate;
public DateTime? SelectedDate
{
get { return _selectedDate; }
set
{
if (_selectedDate == value)
return;
SetProperty(ref _selectedDate,
value,
nameof(SelectedDate));
if (_selectedDate.HasValue)
FetchShiftsForSelectedDate();
}
}
private void FetchShiftsForSelectedDate()
{
ShiftsForSelectedDate = _shiftService.GetShiftsForSelectedDateAsync(_selectedDate.Value);
}
}
MockShiftService (implements the IShiftService interface):
public class MockShiftService
: IShiftService
{
private IList<Shift> _shifts;
public MockShiftService()
{
Initialize();
}
public IEnumerable<Shift> GetShiftsForEmployeeAsync(int employeeId)
{
return _shifts;
}
public IEnumerable<Shift> GetShiftsForSelectedDateAsync(DateTime selectedDate)
{
var endDate = selectedDate.Date.Add(new TimeSpan(23, 59, 59));
return _shifts
.Where(s => s.StartDate <= endDate && s.EndDate >= selectedDate)
.ToList();
}
public Shift GetShiftByIdAsync(int shiftId)
{
return _shifts.First((shift) => shift.Id == shiftId);
}
private void Initialize()
{
var shifts = new List<Shift>();
// The in memory array gets populated here which
// is straight forward creating instances of the
// 'Shift' class and assigning it's properties before
// adding it to the 'shifts' collection. I left
// this code out to keep it as short as possible.
}
}
UPDATE:
I have referenced my project directly to the debug assemblies of MvvmCross and figured out that the exception is thrown on line 127 of the MvxTaskBasedBindingContext class and always happens on the second iteration. From this I conclude that the collection is changed during the first iteration. Unfortunately I cannot figure out why or how.
I noticed that the MvxTaskBasedBindingContext replaces the MvxBindingContext (changed by softlion on 11-5-2016). When I force my application to use the MvxBindingContext class all works well (although a bit laggy). This makes me believe the problem is in the MvxTaskBasedBindingContext but I really can't figure out why, any help would be greatly appreciated.
UPDATE 2:
After some more debugging and fiddling around I found out that the exception is related to the bindings set by my CalendarTableViewCell class (which should provide the layout for each item in the tableview defined in my CalendarViewController. When I comment out the bindings in the CalendarTableViewCell class the exception does not occur (see my code above). I still don't know what could be wrong though.
You can make use of DelayBind in your CalendarTableViewCell to delay binding until your DataContext gets set on your BindingContext
public partial class CalendarTableViewCell : MvxTableViewCell
{
...
public override void LayoutSubviews()
{
base.LayoutSubviews();
this.DelayBind(() =>
{
var set = this.CreateBindingSet<CalendarTableViewCell, Shift>();
set.Bind(StartTimeLabel).To(vm => vm.StartDate).WithConversion("StringFormat", "HH:mm");
set.Bind(EndTimeLabel).To(vm => vm.EndDate).WithConversion("StringFormat", "HH:mm");
set.Bind(ColorBarView).For("BackgroundColor").To(vm => vm.Color).WithConversion("RGB");
set.Bind(TitleLabel).To(vm => vm).WithConversion("ConcatenatedEventTitle");
set.Bind(LocationLabel).To(vm => vm.Location);
set.Apply();
});
}
}
The problem will not be fixed with delay binding.
The problem is that the Lists are enumerated in a Task, which can be modified while the enumeration is going on.
Task.Run(() =>
{
foreach (var binding in this._viewBindings)
{
foreach (var bind in binding.Value)
{
bind.Binding.DataContext = this._dataContext;
}
}
foreach (var binding in this._directBindings)
{
binding.Binding.DataContext = this._dataContext;
}
});
Before enumerating need to create copy of collection ToList() or ToArray().
This bug has beed already reported.
Link
I am presenting a simple UIPageViewController and adding some really simple and stupid child view controllers to it. When the UIPageViewController gets dismissed I am disposing all child view controllers, the ones currently not displayed (listed in ChildViewControllers) and the one displayed (listed in ViewControllers). The not displayed ones get released, the displayed one gets not.
I have broken this down to a simple failing test, so I am sure it's not about the content of the child view controllers or some other issues around that. I have no idea what is retaining it.
Sample:
Master (presented)
public class MasterDialog : UIPageViewController
{
public event EventHandler OnDialogClosed;
private UIBarButtonItem _backButton;
public MasterDialog() : base(
UIPageViewControllerTransitionStyle.Scroll,
UIPageViewControllerNavigationOrientation.Horizontal,
UIPageViewControllerSpineLocation.None,
25)
{
_backButton = new UIBarButtonItem(UIBarButtonSystemItem.Cancel);
_backButton.Clicked += Close;
NavigationItem.SetLeftBarButtonItem(_backButton, false);
}
public override void ViewDidDisappear(bool animated)
{
base.ViewDidDisappear(animated);
OnDialogClosed(this, EventArgs.Empty);
}
private void Close(object sender, EventArgs arguments)
{
_backButton.Clicked -= Close;
NavigationController.DismissViewController(true, null);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
Console.WriteLine("Master disposed");
}
}
Master Data Source
public class DataSource : UIPageViewControllerDataSource
{
public override UIViewController GetPreviousViewController(
UIPageViewController pageViewController, UIViewController referenceViewController)
{
var detail = (DetailDialog)referenceViewController;
if (detail.Page - 1 == 0)
return null;
return GetViewController(detail.Page - 1);
}
public override UIViewController GetNextViewController(
UIPageViewController pageViewController, UIViewController referenceViewController)
{
var detail = (DetailDialog)referenceViewController;
return GetViewController(detail.Page + 1);
}
public UIViewController GetViewController(int page)
{
return new DetailDialog(page);
}
}
Detail (Child)
public class DetailDialog : UITableViewController
{
public int Page { get; private set; }
public DetailDialog(int page) : base(UITableViewStyle.Plain)
{
Page = page;
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
Console.WriteLine("Detail init: " + Page + " / " + GetHashCode());
var label = new UILabel();
label.Text = "#" + Page;
label.ContentMode = UIViewContentMode.Center;
label.Frame = new System.Drawing.RectangleF(0, 100, 320, 50);
label.BackgroundColor = UIColor.Green;
Add(label);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
Console.WriteLine("Detail disposed: " + Page + " / " + GetHashCode());
}
}
The opening dialog (starting point)
public class StartDialog : UIViewController
{
private DataSource _dataSource;
private MasterDialog _master;
public StartDialog()
{
Title = "WTF";
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
var button = new UIButton(UIButtonType.Custom);
button.SetTitle("Open", UIControlState.Normal);
button.BackgroundColor = UIColor.Green;
button.Frame = new System.Drawing.RectangleF(20, 150, 280, 44);
Add(button);
button.TouchDown += OpenMasterDialog;
}
private void OpenMasterDialog(object sender, EventArgs arguments)
{
_dataSource = new DataSource();
_master = new MasterDialog();
_master.DataSource = _dataSource;
_master.OnDialogClosed += HandleOnDialogClosed;
_master.SetViewControllers(
new [] { _dataSource.GetViewController(1) },
UIPageViewControllerNavigationDirection.Forward,
false,
null
);
NavigationController.PresentViewController(
new UINavigationController(_master),
true,
null
);
}
private void HandleOnDialogClosed(object sender, EventArgs e)
{
_dataSource.Dispose();
_dataSource = null;
Console.WriteLine("Before: " + _master.ChildViewControllers.Length +
"/" + _master.ViewControllers.Length + ")");
var childs = _master
.ChildViewControllers.ToList()
.Union(_master.ViewControllers);
foreach (UIViewController child in childs)
{
child.RemoveFromParentViewController();
child.Dispose();
}
Console.WriteLine("After: " + _master.ChildViewControllers.Length +
"/" + _master.ViewControllers.Length + ")");
_master.OnDialogClosed -= HandleOnDialogClosed;
_master.Dispose();
_master = null;
}
}
I might be misunderstanding your code/intent but in this case it seems to me that everything is almost fine. Anyway here's my findings...
Detail disposed: 1 / 36217954
After: 0/1)
Line #2 shows /1 which I assume to be the issue. This is normal because you're re-surfacing the view controller, IOW the code:
_master.ViewControllers.Length
calls the viewControllers selector on the UIPageViewController. That returns: "The view controllers displayed by the page view controller." which is still DetailDialog at that point (even if master is not displayed anymore).
This is not Xamarin specific, an ObjC application would return the same (native) instance at that same point of time.
That's explained - but it still not freed later, why ?
Under the new Dispose semantics the managed object is kept, after Dispose, as long as the native side requires it (but without a native reference so it can be natively released and, subsequently, released on the managed side).
In this case the lifecycle of the native object is not yet over (i.e. iOS still has reference to it) so it remains alive on the managed side.
_master.Dispose();
_master = null;
This removes the managed references to _master but again (same as above) it won't be freed (and neither will be DetailDialog) as long as the native _master instance is used (with native references).
So who got a reference to _master ?
NavigationController.PresentViewController(
new UINavigationController(_master),
^ That creates a UINavigationController and as long as it's alive the there are references to the others.
When I dispose of the UINavigationController (I kept it in a field) then the Master* and Detail* instances disappear from HeapShot.
_nav.Dispose();
_nav = null;
I would like to add items to list box.
It's completely fine in the button click function.
However, if I put it in other function, it doesn't work.
or in other words, I can see "start" in the box, but not the "mission".
Thanks
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("start");
listBox1.Items.Add("start");
token = textBox1.Text;
shipid = textBox2.Text;
host = textBox3.Text;
shipid = shipid.Replace(",", "%2C");
System.Timers.Timer t = new System.Timers.Timer(5000);
t.Elapsed += new System.Timers.ElapsedEventHandler(Mission3);
t.AutoReset = true;
t.Enabled = true;
}
private void Mission3(object source, System.Timers.ElapsedEventArgs e)
{
progress = action(progress, 0, 0, "0");
listBox1.Items.Add("mission");
}
This might be a trivial thing but I am new to xamarin/monotouch or iPhone/IOS development,
I am trying to make an application(sort of gallery+mail) in which I want to share the image.At longpress
it should open the contacts from where I can select the person from contact and it should take me to the
mailing view. I do not want to do this usung "pushview", but want to just switch the views using "PresentModalViewController"
Now I am getting the addressbook but as soon as I select the contact person instead of displaying the
mailing view it goes back to the homeview.
I even tried dismissing the view after the mailing view is dismissed but the output is still the same..
please help out with this.
what I am doing is as follows:(just merged the two programs given on Xamarin website)
using System;
using System.Drawing;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using MonoTouch.AddressBookUI;
using MonoTouch.MessageUI;
namespace ChooseContact
{
public partial class ChooseContactViewController : UIViewController
{
public ChooseContactViewController () : base ("ChooseContactViewController", null)
{
}
public override void DidReceiveMemoryWarning ()
{
// Releases the view if it doesn't have a superview.
base.DidReceiveMemoryWarning ();
// Release any cached data, images, etc that aren't in use.
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
ABPeoplePickerNavigationController _contactController;
UIButton _chooseContact;
UILabel _contactName;
_chooseContact = UIButton.FromType (UIButtonType.RoundedRect);
_chooseContact.Frame = new RectangleF (10, 10, 200, 50);
_chooseContact.SetTitle ("Choose a Contact", UIControlState.Normal);
_contactName = new UILabel{Frame = new RectangleF (10, 70, 200, 50)};
View.AddSubviews (_chooseContact, _contactName);
_contactController = new ABPeoplePickerNavigationController ();
_chooseContact.TouchUpInside += delegate {
this.PresentModalViewController (_contactController, true); };
_contactController.SelectPerson += delegate(object sender, ABPeoplePickerSelectPersonEventArgs e) {
//_contactName.Text = string.Format(e.Person.GetEmails());
_contactName.Text = String.Format ("{0} {1}", e.Person.FirstName, e.Person.LastName);
_contactController.DismissModalViewControllerAnimated (true);
MFMailComposeViewController _mailController;
string[] Emailid = {"hz#gmail.com"};
_mailController = new MFMailComposeViewController ();
_mailController.SetToRecipients (Emailid);
_mailController.SetSubject ("mail test");
_mailController.SetMessageBody ("this is a test", false);
_mailController.Finished += ( object s, MFComposeResultEventArgs args) => {
Console.WriteLine (args.Result.ToString ());
args.Controller.DismissModalViewControllerAnimated (true);
};
this.PresentModalViewController (_mailController, true);
};
}
public override void ViewDidUnload ()
{
base.ViewDidUnload ();
// Clear any references to subviews of the main view in order to
// allow the Garbage Collector to collect them sooner.
//
// e.g. myOutlet.Dispose (); myOutlet = null;
ReleaseDesignerOutlets ();
}
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
// Return true for supported orientations
return (toInterfaceOrientation != UIInterfaceOrientation.PortraitUpsideDown);
}
}
}
Try removing this line
_contactController.DismissModalViewControllerAnimated (true);