new to Xamarin / MonoTouch
I have a Universal storyboard App (ipad and iphone)
I use storyboards
So I have linked a segue from the MainViewController
to a secondaryViewController (educateViewController).
I do not use nor do I want to use a navigation controller (I'm able to do this in native iOS)
I'm struggling with PerformSegue call which results in
System.Exception: Selector invoked from objective-c on a managed
object of type MyTestApp.educateViewController (0x9827E50) that has
been GC'ed ---> System.Exception: No constructor found for
MyTestApp.educateViewController::.ctor(System.IntPtr)
I have
private educateViewController educateScreen;
and inside ViewDidLoad()
educateScreen = new educateViewController();
partial void educate (MonoTouch.Foundation.NSObject sender)
{
solveIt(sender);
if (valid) {
if (UserInterfaceIdiomIsPhone) {
this.PerformSegue("educate", this); <<<< error occurs here
} else if (UserInterfaceIdiomIsiPad) {
this.Instructor.Hidden = false;
}
}
}
Segue should only be called if it is on the iPhone
All help welcome, thanks in advance
You need to make sure the EducateViewController implements the following constructor:
public EducateViewController (IntPtr handle) : base (handle)
{
}
That should allow the view controller to be instantiated from the Storyboard.
To Perform Segue:
this.PerformSegue("segueIdentifier here", this);
On Target class, Add:
protected MyCustomController(IntPtr handle) : base(handle)
{
// Note: this .ctor should not contain any initialization logic.
}
Note: Please change 'MyCustomController' as your target controller name.
Related
I’m new in xamarin ios and I need to add view in existing project. Project use mvvmcross framework.
I’ve done:
Created PerevozkiViewModelClass :MvxViewModel in Core project
Add UI View controller with storydoard (P.S. BaseView extends MvxViewController)
public partial class PerevozkiView : BaseView
{
public PerevozkiView() : base("PerevozkiView", null)
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
var set = this.CreateBindingSet<PerevozkiView, PerevozkiViewModel>();
set.Apply();
}
}
Delete PerevozkiView.Storyboard
4.Add PerevozkiView.xib and in file owner specify PerevozkiView (I cant choose it from list, so I just hardcode “PerevozkiView as file owner)
After deploy in IOS simulator I’ve got exception:
Foundation.MonoTouchException
Сообщение = Objective-C exception thrown. Name: NSInternalInconsistencyException Reason: -[UIViewController _loadViewFromNibNamed:bundle:] loaded the "PerevozkiView" nib but the view outlet was not set here in Main:
public class Application
{
// This is the main entry point of the application.
static void Main(string[] args)
{
// if you want to use a different Application Delegate class from "AppDelegate"
// you can specify it here.
UIApplication.Main(args, null, "AppDelegate");
}
}
I have no idea what is wrong. Pls help
In a cross platform Xamarin app built with the MvvmCross framework I'm using a ToggleButton Widget in an Android .axml layout. I've bound the Checked property to a View Model property using a converter using the following binding syntax:
Checked MarketBuySellViewModel.Direction, Converter=DirectionBool, ConverterParameter='Sell'
Everything works well. On the iOS side, it appears you can use UIButton as a ToggleButton by using the Selected property. This implies that the following binding should achieve what I want on iOS:
set.Bind (SellButton).For(b => b.Selected).To (vm => vm.MarketBuySellViewModel.Direction).WithConversion("DirectionBool", "Sell");
I don't get any binding errors in the application output but the binding itself doesn't seem to work. Clicking the button doesn't set the Direction property and setting the direction to a different value does not set the Selected property on the UIButton.
Do I need to create a Custom Binding or am I simply setting up the binding incorrectly?
I also tried using a UISegmentedControl to achieve the same effect. Is binding to this control supported at all in MvvmCross? I don't see any reference to it in the source code. Does this mean I need to create custom bindings for it too?
For the UIButton, I don't believe there's any included Selected binding built into MvvmCross. Because of this - and because Selected doesn't have a simple paired event SelectedChanged, then I believe Selected binding should work one-way (from ViewModel to View) but not two-way.
There is a binding for the On of a UISwitch control and that's the control I've seen used most in these situations.
If you wanted to add a custom 2-way binding for Selected then I guess you'd have to do this using the ValueChanged event (but would need to check that is correct).
To do so, you'd just build a target binding something like:
public class MvxUIButtonSelectedTargetBinding : MvxPropertyInfoTargetBinding<UIButton>
{
public MvxUIButtonSelectedTargetBinding(object target, PropertyInfo targetPropertyInfo)
: base(target, targetPropertyInfo)
{
var view = View;
view.ValueChanged += HandleValueChanged;
}
private void HandleValueChanged(object sender, System.EventArgs e)
{
var view = View;
if (view == null)
return;
FireValueChanged(view.Selected);
}
public override MvxBindingMode DefaultMode
{
get { return MvxBindingMode.TwoWay; }
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (isDisposing)
{
var view = View;
if (view != null)
{
view.ValueChanged -= HandleValueChanged;
}
}
}
}
and this could be registered in Setup in protected override void FillTargetFactories(IMvxTargetBindingFactoryRegistry registry) using something like:
registry.RegisterPropertyInfoBindingFactory(typeof(MvxUIButtonSelectedTargetBinding), typeof(UIButton),
"Selected");
Similarly, I don't believe anyone has added a two way UISegmentedControl binding yet - but would happily see one added.
Building a two way UISegmentedControl binding would be quite straight-forward - you'd just have to bind to the pair SelectedSegment and ValueChanged - with code similar to above.
Alternatively, you could switch to using a custom MySegmentedControl which had a nicer Value`ValueChanged` pair which would automatically work without a custom binding - e.g.:
public class MySegmentedControl : UISegmentedControl
{
// add more constructors if required
public int Value
{
get { return base.SelectedSegment; }
set { base.SelectedSegment = value; }
}
}
If any or all of these custom bindings are needed, then the Mvx project is happy to get these bindings added as issues or pull requests along with test/demo UIs in the https://github.com/slodge/MvvmCross-Tutorials/blob/master/ApiExamples/ApiExamples.Touch/Views/FirstView.cs project
Could be helpful to someone else, so i'm sharing my experience. I needed a two way binding for UISegmentedControl.SelectedSegment property to a ViewModel. The one way biding (ViewModel => View) works by default. I couldn't able to properly utilize the solution proposed by Stuart - to subclass the UISegmentedControl. I tried to ensure that the linker does not rip off the new custom control code, but this didn't help me a bit. So a perfectly viable solution is the one with MvxPropertyInfoTargetBinding. Here is the code working ok for me:
public class MvxUISegmentedControlSelectedSegmentTargetBinding : MvxPropertyInfoTargetBinding<UISegmentedControl>
{
public MvxUISegmentedControlSelectedSegmentTargetBinding(object target, PropertyInfo targetPropertyInfo)
: base(target, targetPropertyInfo)
{
this.View.ValueChanged += HandleValueChanged;
}
private void HandleValueChanged(object sender, System.EventArgs e)
{
var view = this.View;
if (view == null)
{
return;
}
FireValueChanged(view.SelectedSegment);
}
public override MvxBindingMode DefaultMode
{
get { return MvxBindingMode.TwoWay; }
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (isDisposing)
{
var view = this.View;
if (view != null)
{
view.ValueChanged -= HandleValueChanged;
}
}
}
}
public class Setup : MvxTouchSetup
{
...
protected override void FillTargetFactories(IMvxTargetBindingFactoryRegistry registry)
{
registry.RegisterPropertyInfoBindingFactory(typeof(MvxUISegmentedControlSelectedSegmentTargetBinding), typeof(UISegmentedControl), "SelectedSegment");
}
}
I want to use a third party view controller that already inherits from UIViewController (https://bitbucket.org/thedillonb/monotouch.slideoutnavigation/src/f4e51488598b/MonoTouch.SlideoutNavigation?at=master), how would I integrate that with MVVMCross?
I could just take the source and change it to inherit from MvxViewController, but guessing I will run into this with other libraries.
Do I need to implement all the interfaces MvxViewController does? IMvxTouchView? IMvxEventSourceViewController?
For this particular case, where you don't actually want to do any data-binding so you can just use a custom presenter - e.g. see #Blounty's answer, or see this project demo - https://github.com/fcaico/MvxSlidingPanels.Touch
If you ever do need to convert third party ViewController base classes so that they support data-binding, then the easiest way is exactly what you guessed:
inherit from them to provide an EventSource-ViewController
inherit from the EventSource-ViewController to add the Mvx BindingContext
This technique is exactly how MvvmCross itself extends each of UIViewController, UITableViewController, UITabBarController, etc in order to provide data-binding.
For example, see:
extending UIViewController to provide an eventsource - MvxEventSourceViewController.cs
extending the event source ViewController to provide a binding context - MvxViewController.cs
Note that because C# doesn't have any Multiple-Inhertiance or any true Mixin support, this adaption of ViewControllers does involve a little cut-and-paste, but we have tried to minimise this through the use of event hooks and extension methods.
If it helps, this iOS technique for a previous MvvmCross version was discussed in Integrating Google Mobile Analytics with MVVMCross (obviously this is out of date now - but the general principles kind of remain the same - we adapt an existing viewcontroller via inheritance)
In Android, a similar process is also followed for Activity base classes - see ActionBarSherlock with latest MVVMCross
You can use a custom view presenter like below, This is pretty much straight out of my app using the SlideOutNavigation.
public class Presenter
: IMvxTouchViewPresenter
{
private readonly MvxApplicationDelegate applicationDelegate;
private readonly UIWindow window;
private SlideoutNavigationController slideNavigationController;
private IMvxTouchViewCreator viewCreator;
public Presenter(MvxApplicationDelegate applicationDelegate, UIWindow window)
{
this.applicationDelegate = applicationDelegate;
this.window = window;
this.slideNavigationController = new SlideoutNavigationController();
this.slideNavigationController.SlideWidth = 200f;
this.window.RootViewController = this.slideNavigationController;
}
public async void Show(MvxViewModelRequest request)
{
var creator = Mvx.Resolve<IMvxTouchViewCreator>();
if (this.slideNavigationController.MenuView == null)
{
// TODO: MAke this not be sucky
this.slideNavigationController.MenuView = (MenuView)creator.CreateView(new MenuViewModel());
((MenuView) this.slideNavigationController.MenuView).MenuItemSelectedAction = this.MenuItemSelected;
}
var view = creator.CreateView(request);
this.slideNavigationController.TopView = (UIViewController)view;
}
public void ChangePresentation(MvxPresentationHint hint)
{
Console.WriteLine("Change Presentation Requested");
}
public bool PresentModalViewController(UIViewController controller, bool animated)
{
Console.WriteLine("Present View Controller Requested");
return true;
}
public void NativeModalViewControllerDisappearedOnItsOwn()
{
Console.WriteLine("NativeModalViewControllerDisappearedOnItsOwn");
}
private void MenuItemSelected(string targetType, string objectId)
{
var type = Type.GetType(string.Format("App.Core.ViewModels.{0}ViewModel, AppCore", targetType));
var parameters = new Dictionary<string, string>();
parameters.Add("objectId", objectId);
this.Show(new MvxViewModelRequest { ViewModelType = type, ParameterValues = parameters });
}
}
I have a custom button which inherits from UIButton. I'm handling the TouchUpInside event and want to display a view on top of the current View. Is there such a thing as Dialogs like in Windows development? Or should I do this in another way?
[MonoTouch.Foundation.Register("HRPicker")]
public class HRPicker : UIButton
{
public HRPicker () : base()
{
SetUp();
}
public HRPicker(NSCoder coder) : base(coder)
{
SetUp();
}
public HRPicker(NSObjectFlag t) : base(t)
{
SetUp();
}
public HRPicker(IntPtr handle) : base(handle)
{
SetUp();
}
public HRPicker(RectangleF frame) : base(frame)
{
SetUp();
}
public void SetUp()
{
TouchUpInside += HandleTouchUpInside;
}
void HandleTouchUpInside (object sender, EventArgs e)
{
//I want to display a View here on top of the current one.
}
}
Thanks,
Yes, you have a couple options:
ModalViewController - is called from any UIViewController and overlays a ViewController in the foreground.
UIPopoverController - is a native control that takes a UIViewController and has hooks for presentation and dismissal
WEPopoverController - is a re-implementation of UIPopoverController and allows you to customize the layout, size, and color of the Popover container.
ModalViewController: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html
UIPopoverController: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIPopoverController_class/Reference/Reference.html
WEPopoverController: https://github.com/mono/monotouch-bindings/tree/master/WEPopover
Update: Regardless of which option you use you must call the presentation of the Popover / Modal view from the main thread:
using(var pool = new NSAutoReleasePool()) {
pool.BeginInvokeOnMainThread(()=>{
// Run your awesome code on the
// main thread here, dawg.
});
}
The equivalent of dialog in Cocoa is UIAlertView: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIAlertView_Class/UIAlertView/UIAlertView.html
Check out this question for an example of how to use it: Showing an alert with Cocoa
The code should be pretty easy to translate to c# and MonoTouch. But here is a simple example: http://monotouchexamples.com/#19
Given my RIA Service:
[Update]
public void Update(Car car)
{
_carRepository.Update(car);
}
[Update(UsingCustomMethod = true)]
public void UpdateAndClone(Car car)
{
_carRepository.UpdateAndClone(car);
}
How may I "map" SubmitChanges to my Custom update method from my Silverlight client side?
Public void Save(Action<SubmitOperation> submitCallback, object state)
{
_carContext.SubmitChanges(submitCallback, state);
}
Public void SaveAndClone(Action<SubmitOperation> submitCallback, object state)
{
_carContext.SubmitChanges(submitCallback, state);
// _carContext.UpdateAndClone(????)
}
I would like my application to handle the update in two quite different ways according to which action is peformed by the user, but I'm having trouble to understand how my "custom" update should be used.
It seems that I can't have both a "standard" update and a custom update.
So by calling the custom method in the viewmodel before doing .SubmitChanges() solves this issue.