Is there a way to achieve method binding in iOS with MVVMCross ?
I cannot see an example of such a binding in the vids or tutorials...
ImageNavigationViewModel:
public void NavigateLeft()
{
if (!this.HasLeftSisters.Value)
{
return;
}
this.currentNodeIndex--;
this.Update();
}
ImageNavigationView:
private UIButton navigateLeftButton;
...
var set = this.CreateBindingSet<ImageNavigationView, ImageNavigationViewModel>();
set.Bind(this.navigateLeftButton).To(vm => vm.NavigateLeft);
I have a compile-time error since it's expecting an object (ICommand).
I tried this too:
set.Bind(this.navigateLeftButton).To("NavigateLeft");
And have runtime error: Failed to create target binding for binding TouchUpInside for NavigateLeft.
I ended up adding a ICommand to my view model, which is a bit disappointing since I "method bind" just find in Android.
Rio Method binding is available in iOS
It's demonstrated in https://www.youtube.com/watch?v=8-5XQlcVj2Y with sample cod ein https://github.com/MvvmCross/NPlus1DaysOfMvvmCross/blob/master/N-36-Rio/BindMe.Touch/Views/FirstView.cs#L58
Your line:
set.Bind(this.navigateLeftButton).To("NavigateLeft");
should work - but you will need the method binding plugin added to the Touch UI project to enable this extension.
Related
I have no experience with iOS, but I am trying to redesign my Android Project for the iOS Guys to use it as well for iOS.
After search in internet I find out that this can happens by using the page factory and locating elements by #iOSFindBy,
After trying to use #iOSFindby for locating element using the page factory method, the compiler indicate that it is deprecated.
#iOSFindBy (Accessibility = "button_login")
#AndroidFindBy(id = "net.myApp.int:id/loginBtn")
private MobileElement login_Button2;
what Can I use instead of this?
I saw also in Appium java client (https://static.javadoc.io/io.appium/java-client/7.0.0/index.html?deprecated-list.html) :
*io.appium.java_client.pagefactory
Annotation Type iOSFindBy
Deprecated.
UIAutomation is going to get deprecated. Use iOSXCUITFindBy instead It is recommended to use XCUITest
#Retention(value=RUNTIME) #Target(value={FIELD,TYPE})
#Repeatable(value=iOSFindBySet.class) public #interface iOSFindBy
Used to mark a field on a Page Object to indicate an alternative mechanism for locating the element or a list of elements. Used in conjunction with PageFactory this allows users to quickly and easily create PageObjects. using iOS UI selectors, accessibility, id, name, class name, tag and xpath*
but I dont know if this is the solution and how to use
If I use it in my Code also get Error:
#iOSXCUITFindBy Accessibility = "button_login"
#AndroidFindBy(id = "net.myApp.int:id/loginBtn")
private MobileElement login_Button1;
Annotation are not allowed here.
Thanks for any Tip in advance
The best way to know how things work is to check related tests in appium-java-client repository on github:
#iOSXCUITFindBy(accessibility = "IntegerB")
private MobileElement textField2;
So in your case, it should be:
#iOSXCUITFindBy(accessibility = "button_login")
#AndroidFindBy(id = "net.myApp.int:id/loginBtn")
private MobileElement login_Button1;
I've got a Xamarin Forms interface that defines a Bluetooth controller. I'm following the usual technique when trying to create an Android specific implementation of this (I will also do an iOS one when I get this working).
I define my interface as follows :
namespace ArduinoRobotController.Models
{
public interface BluetoothControllerInterface
{
List<string> GetPairedDevices();
..
Then I have my platform specific implementation like this :
[assembly: Xamarin.Forms.Dependency(typeof(BluetoothControllerInterface))]
namespace ArduinoRobotController.Droid.Implementations
{
public class BluetoothController : BluetoothControllerInterface
{
..
Then finally back in one of my view models, I have this code to get the platform specific instance I need :
BluetoothControllerInterface bt = Xamarin.Forms.DependencyService.Get<BluetoothControllerInterface>();
It builds and runs, but crashes on the line above. The error states :
System.MissingMethodException: Default constructor not found for type ArduinoRobotController.Models.BluetoothControllerInterface at SystemRuntimeType.CreateInstanceMono
.. etc.
I've tried lots of different ways around doing this, including calling to register the implementation in normal code rather than as [assembly etc. Any help on this really appreciated.
your registration needs to point to the concrete class, not the interface
[assembly: Xamarin.Forms.Dependency(typeof(BluetoothController))]
I am writing an application with Xamarin.Android with MvvmCross. I want my Activity to inherit from MvxAppCompatActivity so that I can use fragments. Here is my base class:
public class BaseActivity<TViewModel> : MvxAppCompatActivity<TViewModel> where TViewModel : MvxViewModel
{
public new TViewModel ViewModel
{
get { return base.ViewModel; }
set { base.ViewModel = value; }
}
}
I get this error on the OnCreate of my Activity:
Failed resolution of: Landroid/support/v7/appcompat/R$drawable; Didn't
find class "android.support.v7.appcompat.R$drawable" on path:
DexPathList...
But if I change MvxAppCompatActivity to MvxActivity it works fine...why?
I downloaded your solution and tried to build the Android project. It fails with 18 occurrences of the same error:
error: No resource identifier found for attribute 'loginButtonBackgroundColor' in package ...
So after a little inspection of your solution, I did the following steps to solve your issue:
1) In login_screen.axml I saw you had this line:
xmlns:[YOURNAMESPACE]="http://schemas.android.com/apk/res/[YOUR PACKAGE]"
Which is unnecessary. After removing it, and changing the lines [YOURNAMESPACE]:loginButtonBackgroundColor=... to local:loginButtonBackgroundColor=... the build succeeds.
2) I saw some layout files are located inside the /drawable folder (button_round_corner.xml, input_box.xml and login_button.xml). I moved them to the /layout folder and fixed the issues the change produced (only two).
3) Made Setup class inherit from MvxAppCompatSetup.
4) Added a RegisterAttribute over the LoginButton control. So the class definition looks like this:
using Android.Runtime;
...
namespace Xxx.Droid.Components
{
[Register(nameof(LoginButton))]
public class LoginButton : FrameLayout, IMvxNotifyPropertyChanged
{
...
}
}
And that's it! Probably (2) was not necessary, but leaving it here just in case.
It could be several things but it is probably the lack of some android support packages. Mainly the lack of Xamarin.Android.Support.Design gives that error. So check if you have that added and if not add it and it should solve your problem.
If it doesn't it's highly likely you lack some other android support packages
I have got my PCL model to build now, which took a bit of time making plug-ins, however now in my Android UI project I get two errors when building it.
First error is:
The type 'System.Collections.ObjectModel.ObservableCollection`1<T0>' is defined in an assembly that is not referenced.
You must add a reference to assembly 'System.Windows, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e,
Retargetable=Yes'. C:\ENM\Main\src\prod\Mobile\Stakeholder\UI.Android.vNext\Views\LocationsMapView.cs 40 32 UI.Android.vNext
The second error is:
foreach statement cannot operate on variables of type
'System.Collections.ObjectModel.ObservableCollection`1<BK.EMS.Stakeholder.Model.ViewModels.LocationViewModel>'
because 'System.Collections.ObjectModel.ObservableCollection`1<BK.EMS.Stakeholder.Model.ViewModels.LocationViewModel>'
does not contain a public definition for 'GetEnumerator'
C:\ENM\Main\src\prod\Mobile\Stakeholder\UI.Android.vNext\Views\LocationsMapView.cs 40 32 UI.Android.vNext
I have referenced the System.Windows assembly from the System.Windows.Droid project, which is supposed to forward ObservableCollection<>.
The lines where the error occurs:
private void AddLocationOverlays()
{
if (_itemizedOverlay.Size() > 0) _itemizedOverlay.ClearOverlayItems();
RunOnUiThread(() =>
{
foreach (var location in ViewModel.Locations)
{
_itemizedOverlay.AddOverlayItem(location);
}
_mapView.Invalidate();
});
}
The Locations property in my ViewModel looks like this:
public ObservableCollection<LocationViewModel> Locations
{
get { return _locations; }
set
{
_locations = value;
RaisePropertyChanged(() => Locations);
}
}
Nothing too complicated and works fine in the non-PCL models...
So how do I get around and fix this?
We now have a solution to this problem - see fix from Daniel Plaisted in Portable Class Library strong assembly reference problems in MonoTouch/MonoDroid
This fix is checked in at https://github.com/slodge/MvvmCross/commit/f6a88048467838e5ac5ca687744dc0b2d1958aa8
Update : See other answer. It appears we now have a solution to this problem!
I believe this is linked to this problem - Portable Class Library strong assembly reference problems in MonoTouch/MonoDroid
Which is linked to: https://github.com/slodge/MvvmCross/issues/41
This is raised with Xamarin as a bug: https://bugzilla.xamarin.com/show_bug.cgi?id=8035 and
I'm afraid I don't understand the recommended Strong Signing solutions right now.
Please upvote the bug report to alert the Microsoft PCL and Xamarin teams about this. The MS and Xamarin teams are talking to each other on this (albeit through me!), and I am hopeful we will find a way for either Microsoft or Xamarin to ship some signed DLLs.
In the meantime, some possible workarounds are:
Use IEnumerable access instead of ObservableCollection - the collection can still be an ObservableCollection instance, just don't reference it as an ObservableCollection in the UI code.
Try putting your iterating code in a class library rather than in an application project - bizarre as it feels, the compiler seems perfectly happy building the same code when its in a library rather than in an application
Try building in MonoDevelop with the Mono compiler - this doesn't seem to have the same strong name reference checks.
Looking at your sample code I would just try:
private ObservableCollection<LocationViewModel> _locations;
public IEnumerable<LocationViewModel> Locations
{
get { return _locations; }
set
{
if (value != null && !(value is ObservableCollection<LocationViewModel>)
{
throw new Exception("You must Set an ObservableCollection");
}
_locations = (ObservableCollection<LocationViewModel>)value;
RaisePropertyChanged(() => Locations);
}
}
then AddLocationOverlays could stay the same.
The only problem with this would be if you then wanted to bind to INotifyCollectionChanged on this collection - but I think you can find a way around this too if needed - e.g. you could somehow expose another INotifyCollectionChanged hook, or you could try using a hack involving an intermediary class library.
I accept that for now these are workarounds not solutions :/
First of all I would like to remark I am new with the concept of prism, DI and containers. I am looking on one of the code samples provided with the Prism Library:
The code simply injects a view with the "Hello World" string (in a TextBlock element) to a region in the shell.
When the application starts-up, it creates a new BootStrapper instance, which creates and initializes the shell:
public class Bootstrapper : UnityBootstrapper
{
protected override DependencyObject CreateShell()
{
return Container.Resolve<Shell>();
}
protected override void InitializeShell()
{
base.InitializeShell();
Application.Current.RootVisual = (UIElement)this.Shell;
}
protected override void ConfigureModuleCatalog()
{
base.ConfigureModuleCatalog();
ModuleCatalog moduleCatalog = (ModuleCatalog)this.ModuleCatalog;
moduleCatalog.AddModule(typeof(HelloWorldModule.HelloWorldModule));
}
}
My question refers to the method CreateShell(). I couldnt find nowhere in the supplied code (including not in a configuration file or any xaml file...) where do they register the type Shell, and even if it was registered - the supplies Shell class doesnt implement any interface... what is the meaning of resolving a specific type?
the Shell implementation:
public partial class Shell : UserControl
{
public Shell()
{
InitializeComponent();
}
}
This looks like a magic to me, so I tried to create my own type (MyType) and resolve it the same way:
Container.Resolve<MyType>();
By setting a breakepoint inside MyType constructor, I saw that it DID resolved MyType. Can somebody please explain to me how does it work?
These couple of threads should answer your question:
http://compositewpf.codeplex.com/Thread/View.aspx?ThreadId=230051
Does unity just make clasess with out needing anything registered?
Additionally, if you are eager to get more detail into how Unity can do this, simple download Unity 2.0 and open the source code that is provided with the installer.
I hope this helps.
Thanks,
Damian
You do not need to register a type you want to resolve. You need to register the dependencies of a type, that you want to resolve. In this case, the Shell doesn't need any dependencies, so you can resolve it simply. But for an example (not really), if your shell getting an interface IService as a parameter, then you must register IService, before you resolve Shell.
Otherwise you will get Dependency Resolution Failed Exception. In Prism 4.1 it will be swallowed silently due to TryResolve.