Catel with Xamarin.Forms - mvvm

I can't get Xamarin.Forms and Catel work together.
I saw this sample but it seems it's out of date.
When I download Catel via NuGet, i get different issues for different versions:
v5.1:
Compile-time exception:
Exception while loading assemblies: System.IO.FileNotFoundException: Could not load assembly 'Obsolete, Version=4.2.4.0, Culture=neutral, PublicKeyToken=1ca091877d12ca03'. Perhaps it doesn't exist in the Mono for Android profile?
v5.0:
Runtime exception (when creating new App();):
Could not load signature of Catel.MVVM.IViewModelFactory:CreateViewModel due to: Could not resolve type with token 01000061 (from typeref, class/assembly System.ComponentModel.IDataErrorInfo, Catel.Core, Version=5.0.0.0, Culture=neutral, PublicKeyToken=null) assembly:Catel.Core, Version=5.0.0.0, Culture=neutral, PublicKeyToken=null type:System.ComponentModel.IDataErrorInfo member:<none>
v4.5.*
Using ViewModelBase:
Runtime exception when creating Application object:
System.TypeLoadException: Could not resolve type with token 01000097 (from typeref, class/assembly System.Reflection.BindingFlags, Catel.Core, Version=4.5.4.0, Culture=neutral, PublicKeyToken=null)
My implementation of IViewModel:
Ok, MainPage loading, binding works, Constructor gets right services via parameters, but, for example, when I call '_uiVisualizerService.Show( subPageViewModel );' from command, it throws 'InvalidCastException'. Last line in Catel log before exception: Injecting properties into type 'SubPage' after construction. But SubPage and SubPageViewModel are absolutely empty.
Details:
---> System.InvalidCastException: Specified cast is not valid.
at Catel.Services.UIVisualizerService+<ShowAsync>d__9.MoveNext () [0x00096]
in C:\CI_WS\Ws\97969\Source\Catel\src\Catel.MVVM\Catel.MVVM.Xamarin.Forms\Services\UIVisualizerService.cs:151
at System.Threading.Tasks.Task.ThrowIfExceptional (System.Boolean includeTaskCanceledExceptions) [0x00011]
in <183b200ee49746d48fc781625979428e>:0
at System.Threading.Tasks.Task'1[TResult].GetResultCore (System.Boolean waitCompletionNotification) [0x0002b]
in <183b200ee49746d48fc781625979428e>:0
at System.Threading.Tasks.Task'1[TResult].get_Result () [0x0000f]
in <183b200ee49746d48fc781625979428e>:0
at Catel.Services.UIVisualizerService.Show (Catel.MVVM.IViewModel viewModel, System.EventHandler``1[TEventArgs] completedProc) [0x00000]
in C:\CI_WS\Ws\97969\Source\Catel\src\Catel.MVVM\Catel.MVVM.Xamarin.Forms\Services\UIVisualizerService.cs:125
at XamarinFormsCatel.ViewModels.MainPageViewModel.OnGo () [0x00015]
in C:\!Work\Test\XamarinFormsCatel\XamarinFormsCatel\XamarinFormsCatel\XamarinFormsCatel\ViewModels\MainPageViewModel.cs:34
at Xamarin.Forms.Command+<>c__DisplayClass3_0.<.ctor>b__0 (System.Object o) [0x00000]
in C:\BuildAgent3\work\ca3766cfc22354a1\Xamarin.Forms.Core\Command.cs:73
at Xamarin.Forms.Command.Execute (System.Object parameter) [0x00000]
in C:\BuildAgent3\work\ca3766cfc22354a1\Xamarin.Forms.Core\Command.cs:107
at Xamarin.Forms.Button.Xamarin.Forms.IButtonController.SendClicked () [0x0000a]
in C:\BuildAgent3\work\ca3766cfc22354a1\Xamarin.Forms.Core\Button.cs:121
at Xamarin.Forms.Platform.Android.AppCompat.ButtonRenderer+ButtonClickListener.OnClick (Android.Views.View v) [0x0000b]
in C:\BuildAgent3\work\ca3766cfc22354a1\Xamarin.Forms.Platform.Android\AppCompat\ButtonRenderer.cs:298
at Android.Views.View+IOnClickListenerInvoker.n_OnClick_Landroid_view_View_ (System.IntPtr jnienv, System.IntPtr native__this, System.IntPtr native_v) [0x0000f]
in <71828dd8fb5f4508815e23d6996c45c2>:0
at (wrapper dynamic-method) System.Object:4c9f6786-8ab0-4bd8-bdb1-4cc7a3d7ddc7 (intptr,intptr,intptr)
-> (Inner Exception #0) System.InvalidCastException: Specified cast is not valid.
at Catel.Services.UIVisualizerService+<ShowAsync>d__9.MoveNext () [0x00096]
in C:\CI_WS\Ws\97969\Source\Catel\src\Catel.MVVM\Catel.MVVM.Xamarin.Forms\Services\UIVisualizerService.cs:151 <---
What i do:
Change defalt Catel.MVVM.dll reference in android project from MonoAndroid to portable-net45+wp8+win8+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10+UAP10. if this is not done, compilation will fail.
MainPage.xaml
<catel:ContentPage ...
xmlns:catel="clr-namespace:Catel.Windows.Controls;assembly=Catel.MVVM">
MainPageViewModel.cs
public class MainPageViewModel : ViewModelBase { }
App.cs
public class App : Catel.Xamarin.Forms.Application<Views.MainPage> { }
MainActivity.cs (Android)
public class MainActivity : Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate( Bundle bundle )
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate( bundle );
Xamarin.Forms.Forms.Init( this, bundle );
var app = new App();
LoadApplication( app );
}
}
Windows 7, 64x.
Xamarin.Forms: 2.3.4.267
Any help very appreciated.

The team is working on improved support for Xamarin.Forms. At the moment there are no examples. The expectation is to finalize v5 support for Xamarin.Forms on this over the next few months.

Related

Weird behaviour of AndroidJavaObject in Unity, when implemented through C#

Rather long post follows. It's fairly complex, needs someone who has worked with Unity Plugins before (creating them, not using them) and I'm not looking to get downvoted because a few common search terms show up. So, please read the entire post.
So, I've been having a rather weird issue happening when I try to call native functions through Unity's AndroidJavaObject
I've built native plugins in the past before, I'm trying to remove my dependancies on having to update multiple JARs each time I need to update my plugins. So, I'm moving a lot of my native Java code from plugins, into Unity itself.
Specifically, there's a way to call native Android functions (i.e. system functions) straight from C#, rather than creating a plugin and calling a function in the plugin that invokes the native function.
For example, earlier, if I had to create a Toast, I'd have to write some native code in Java, export the plugin and then call the function. These days, one can just call the Toast.makeText straight from C# as follows.
Here's how I make the call for a Toast.
public static void Toast (string text, int duration) {
#if UNITY_ANDROID && !UNITY_EDITOR
CreateActivity();
activity.Call("runOnUiThread", new AndroidJavaRunnable ( () => {
new AndroidJavaObject("android.widget.Toast", activity)
.CallStatic<AndroidJavaObject>("makeText", activity, text, duration)
.Call("show");
}) );
#endif
}
and here's the CreateActivity method
private static void CreateActivity () {
#if UNITY_ANDROID && !UNITY_EDITOR
if(activity == null)
activity = new AndroidJavaClass("com.unity3d.player.UnityPlayer").
GetStatic<AndroidJavaObject>("currentActivity");
#endif
}
This works perfectly. However, when I try the same approach for creating an AlertDialog, I get an androidjavaexception java.lang.classnotfoundexception
Here's the relevant code
public static void ShowAlert (string title, string message, string buttonText) {
#if UNITY_ANDROID && !UNITY_EDITOR
CreateActivity();
activity.Call("runOnUiThread", new AndroidJavaRunnable ( () => {
var builder = new AndroidJavaObject("android.app.AlertDialog.Builder", activity);
***//Exception happens in the above line***
builder.Call<AndroidJavaObject>("setMessage", message)
.Call<AndroidJavaObject>("setTitle", title)
.Call<AndroidJavaObject>("setCancelable", false)
.Call<AndroidJavaObject>("setNeutralButton", buttonText)
.Call("show");
}) );
#endif
}
What I've tried
Used android.support.v7.app.AlertDialog.Builder instead of android.app.AlertDialog.Builder
Added the support JARs for v7 & v4 (Specifically android-support-v4 & android-support-v7-appcompat)
Tried creating my own implementation for Unity's JNI and invoking that
All the above failed. (The third one, rather spectacularly)
Now, I tried other classes as well, and most of them work (such as ProgressDialog, which is a subclass of AlertDialog), and those work!
At this point, I'm rather stumped and I can't think of a VALID reason for certain functions to work, and the others to fail.
Any thoughts are appreciated.
EDIT 1: Added LogCat
I/Unity: AndroidJavaException: java.lang.ClassNotFoundException: android.app.AlertDialog.Builder
at UnityEngine.AndroidJNISafe.CheckException () [0x00000] in <filename unknown>:0
at UnityEngine.AndroidJNISafe.CallStaticObjectMethod (IntPtr clazz, IntPtr methodID, UnityEngine.jvalue[] args) [0x00000] in <filename unknown>:0
at UnityEngine.AndroidJavaObject._CallStatic[AndroidJavaObject] (System.String methodName, System.Object[] args) [0x00000] in <filename unknown>:0
at UnityEngine.AndroidJavaObject.CallStatic[AndroidJavaObject] (System.String methodName, System.Object[] args) [0x00000] in <filename unknown>:0
at UnityEngine.AndroidJavaObject.FindClass (System.String name) [0x00000] in <filename unknown>:0
at UnityEngine.AndroidJavaObject._AndroidJavaObject (System.String className, System.Object[] args) [0x00000] in <filename unknown>:0
at UnityEngine.AndroidJavaObject..ctor (System.String className, System.Object[] args) [0x00000] in <filename unknown>:0
at AndroidNative+<ShowAlert>c__AnonSto
The problem you are running into, is that AlertDialog.Builder is a nested class of AlertDialog, and creating nested classes through reflection (which is what AndroidJavaObject is trying to do) requires a slightly different syntax in Java:
android.app.AlertDialog$Builder
There are some other tiny mistakes in your code (that you couldn't know about because your constructor wasn't working):
setNeutralButton requires a callback argument (which can be null)
show has to be called on the AlertDialog itself, not on the builder.
Taking these tiny corrections into consideration, a working code sample looks like this:
public static void ShowAlert(string title, string message, string buttonText)
{
CreateActivity();
activity.Call("runOnUiThread", new AndroidJavaRunnable(() =>
{
var builder = new AndroidJavaObject("android.app.AlertDialog$Builder", activity);
builder.Call<AndroidJavaObject>("setMessage", message)
.Call<AndroidJavaObject>("setTitle", title)
.Call<AndroidJavaObject>("setCancelable", false)
.Call<AndroidJavaObject>("setNeutralButton", buttonText, null)
.Call<AndroidJavaObject>("create")
.Call("show");
}));
}

StructureMap and MongoRepository.1.6.2 .Net 4.5

The Problem:
I am having trouble getting StructureMap to find the default instance for the IRepository<> type in the MongoRepostiory namespace.
The exception message:
"StructureMap Exception Code: 202
No Default Instance defined for PluginFamily MongoDB.Driver.MongoUrl, MongoDB.Driver, Version=1.8.3.9, Culture=neutral, PublicKeyToken=f686731cfb9cc103"
It appears that StructureMap is instantiating the MonogoRepository class with the wrong constructor...
The MonogoRepository has the following constructors:
public class MongoRepository<T> : MongoRepository<T, string>, IRepository<T>, IRepository<T, string>, IQueryable<T>, IEnumerable<T>, IQueryable, IEnumerable where T : MongoRepository.IEntity<string>
{
public MongoRepository();
public MongoRepository(MongoUrl url);
public MongoRepository(string connectionString);
public MongoRepository(MongoUrl url, string collectionName);
public MongoRepository(string connectionString, string collectionName);
}
I want the public MongoRepository(string connectionString); constructor to be called...but it appears that from the exception message, since StructureMap is attempting to resolve MongoUrl, it is not calling the desired one.
I wonder:
Questions:
Have I setup something wrong which is causing the incorrect constructor to be called?
or
Is this the default behaviour, and if so, how do I change it to ensure the desired constructor is called?
The Setup:
I have the following Registry class:
public class IocRegistry : Registry
{
public IocRegistry()
{
this.For(typeof(IRepository<>)).Use(typeof(MongoRepository<>))
.CtorDependency<string>("connectionString")
.Is("MongoServerSettings");
}
}
And the following Container initialization:
public static IContainer Initialize() {
ObjectFactory.Initialize(x =>
{
x.Scan(scan =>
{
scan.TheCallingAssembly();
scan.LookForRegistries();
scan.WithDefaultConventions();
});
});
return ObjectFactory.Container;
}
The IocRegistry is definitely getting hit when I put a break-point in its constructor and debug the application.
The code which consumes the IRepository<> is:
public class ImageContentService : IImageContentService
{
private IRepository<ImageItem> imageRepository;
public ImageContentService(IRepository<ImageItem> imageRepository)
{
this.imageRepository = imageRepository;
}
}
The relevant output of ObjectFactory.Container.WhatDoIHave() (once all registrations have taken place) is:
===========================================================================================================
Configuration Sources:
0) Registry: StructureMap.InitializationExpression, StructureMap, Version=2.6.4.0, Culture=neutral, PublicKeyToken=e60ad81abae3c223
1) Registry: StructureMap.Configuration.DSL.Registry, StructureMap, Version=2.6.4.0, Culture=neutral, PublicKeyToken=e60ad81abae3c223
2) Registry: StructureMap.Configuration.DSL.Registry, StructureMap, Version=2.6.4.0, Culture=neutral, PublicKeyToken=e60ad81abae3c223
3) Registry: Mch.Core.IocRegistry, Mch.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
============================================================================================================================================================================================================================================================================================================================================
PluginType Name Description
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
IRepository`1<T> (IRepository`1<T>) d26c76dd-8550-4d02-bf8a-25c6f0075346 Configured Instance of MongoRepository.MongoRepository`1, MongoRepository.Net45, Version=1.6.2.0, Culture=neutral, PublicKeyToken=null
Scoped as: Transient
d26c76dd-8550-4d02-bf8a-25c6f0075346 Configured Instance of MongoRepository.MongoRepository`1, MongoRepository.Net45, Version=1.6.2.0, Culture=neutral, PublicKeyToken=null
You can tell StructureMap which constructor to use:
x.SelectConstructor<ClassWithTwoConstructors>(()=>new ClassWithTwoConstructors(0));
You can find this in the StructureMap documentation.
I had the exact same issue. In the end I solved it by configuring my MongoRepository in the ObjectFactory initialisation like so:
x.For<IRepository<T>>().Use(() => new MongoRepository<T>("{ConnectionString}","{CollectionName}"));
This way it seems the Structuremap seems to use the correct constructor. Obviosuly you can instantiate the MongoRepository with whichever constructor you prefer.

DbContext not initializing with SQL Server Compact in ASP.Net MVC

I have created a simple project using ASP.Net MVC template in Visual Studion 2013 Express for Web. It does not use any authentication. Then I installed EntityFramework (v6.0.1), EntityFramework.SqlServerCompact packages.
My DbContext class is very simple:
public class EditTestContext : DbContext
{
public EditTestContext() : base("EditTestContext")
{
}
public EditTestContext(string connectionString) : base(connectionString)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer(
new DropCreateDatabaseIfModelChanges<EditTestContext>());
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Configurations.Add(new EditTestConfig());
}
}
The actual context object is created in the Unit of Work class:
public class EditTestUoW:IEditTestUoW,IDisposable
{
private DbContext dbContext;
public EditTestUoW()
{
CreateDbContext();
}
private void CreateDbContext()
{
dbContext = new EditTestContext();//NEW DBCONTEXT OBJECT IS CREATED
dbContext.Configuration.LazyLoadingEnabled = false;
dbContext.Configuration.ProxyCreationEnabled = false;
dbContext.Configuration.ValidateOnSaveEnabled = false;
}
public IRepository<EditTestModel> EditTestRepo
{
get
{
return new EFRepository<EditTestModel>(dbContext);
}
}
}
The connection string being used is:
<add name="EditTestContext" connectionString="Data Source=
|DataDirectory|EditTestDb.sdf;Max Database Size=256;
Max Buffer Size=1024;File Mode=Shared Read;
Persist Security Info=False;" providerName="System.Data.SqlServerCe.4.0" />
Now when I try to access any thing using this Context like:
var rep=UoW.EditTestRepo;
var list=rep.GetAll().ToList();
I am getting following exception on rep.GetAll() function:
System.InvalidOperationException: Sequence contains no matching element
On digging deeper, IQueryable from Repository class (DbSet<EditTest>) is throwing following exception:
The context cannot be used while the model is being created. This exception may
be thrown if the context is used inside the OnModelCreating method or if the same
context instance is accessed by multiple threads concurrently. Note that instance
members of DbContext and related classes are not guaranteed to be thread safe.
I thought it might have been caused by ninject, but it is still there even after I removed it.
What I am doing wrong here or something (some assembly reference etc.) is missing?
Well after some other search on the issue, I got this MSDN forum link. As was suggested by Rowan, I tried to manually initialize the context using following statement in my EFRepository class:
dbContext.Database.Initialize(false);
The application failed way before it was hitting the GetAll() method. But this exposed the stack trace which gave me some direction:
[InvalidOperationException: Sequence contains no matching element]
System.Linq.Enumerable.Single(IEnumerable`1 source, Func`2 predicate) +2614017
System.Data.Entity.Utilities.DbProviderManifestExtensions.GetStoreTypeFromName
(DbProviderManifest providerManifest, String name) +146
.....Other Lines.....
System.Data.Entity.Internal.InternalContext.Initialize() +31
System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType
(Type entityType) +38
System.Data.Entity.Internal.Linq.InternalSet`1.Initialize() +138
System.Data.Entity.Internal.Linq.InternalSet`1.get_InternalContext() +38
System.Data.Entity.Infrastructure.DbQuery`1.System.Linq.IQueryable
.get_Provider() +99
System.Linq.Queryable.Any(IQueryable`1 source) +50
Then searching for DbProviderManifestExtensions.GetStoreTypeFromName revealed that this is the line where EF was trying to get column type. I had specified UNIQUEIDENTIFIER for my Id column:
Property(x=> x.Id).HasColumnType("UNIQUEIDENTIFIER")
Once I commented this, all was well.
Though there is a request on Codeplex to provide the proper error message in case the column type is not valid for database provider.

System.InvalidProgramException Invalid IL code in System.Data.Objects.ObjectContext:.ctor (string,string): method body is empty

Im using mono(3.0.3) on a raspberry pi. Everything is working properly except entity framework. I can login with no problem into my site but the second I enter an area where there is entity framework i get the following error with XSP:
Application Exception
System.InvalidProgramException
Invalid IL code in System.Data.Objects.ObjectContext:.ctor (string,string): method body is empty.
Description: HTTP 500.Error processing request.
Details: Non-web exception. Exception origin (name of application or object): AdwenModel.
Exception stack trace:
at AdwenModel.AdwenEntities1..ctor (System.String connectionString) [0x00000] in <filename unknown>:0
at AdwenWeb.App_Code.AdwenConnection.getDataContextAdwen () [0x00000] in <filename unknown>:0
at AdwenWeb.Management.overview.createObjectTable () [0x00000] in <filename unknown>:0
at AdwenWeb.Management.overview.Page_Load (System.Object sender, System.EventArgs e) [0x00000] in <filename unknown>:0
at System.Web.UI.Control.OnLoad (System.EventArgs e) [0x00029] in /opt/mono-3.0/mono/mcs/class/System.Web/System.Web.UI/Control.cs:1211
at System.Web.UI.Control.LoadRecursive () [0x00031] in /opt/mono-3.0/mono/mcs/class/System.Web/System.Web.UI/Control.cs:1641
at System.Web.UI.Page.ProcessLoad () [0x0004a] in /opt/mono-3.0/mono/mcs/class/System.Web/System.Web.UI/Page.cs:1490
at System.Web.UI.Page.ProcessPostData () [0x0004d] in /opt/mono-3.0/mono/mcs/class/System.Web/System.Web.UI/Page.cs:1475
at System.Web.UI.Page.InternalProcessRequest () [0x001bf] in /opt/mono-3.0/mono/mcs/class/System.Web/System.Web.UI/Page.cs:1442
at System.Web.UI.Page.ProcessRequest (System.Web.HttpContext context) [0x00062] in /opt/mono-3.0/mono/mcs/class/System.Web/System.Web.UI/Page.cs:1269
Version Information: 3.0.3 (master/c1b505c Thu Dec 6 09:17:47 UTC 2012); ASP.NET Version: 4.0.30319.17020
Don't really know what else could be wrong.
I don't know much about the Entity Framework support in Mono but what I do know is that they have included EF6 in Mono, and System.Data.Objects is no longer the namespace for ObjectContext in EF6. Whatever is causing the failure should be looking for System.Data.Entity.Core.Objects.ObjectContext instead.
Hope this helps.

Entity Framework 4.3 Migration Exception when Update-Database

After upgrading from EF 4.2 and Migration to EF 4.3 and enabling migration,restarting Visual studio and everything , whenever I try to call Update-Database/Add-Migration I get this:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ArgumentException:
The parameter is incorrect. (Exception from HRESULT: 0x80070057
(E_INVALIDARG))
--- End of inner exception stack trace ---
at System.RuntimeType.InvokeDispMethod(String name, BindingFlags invokeAttr, Object target, Object[] args, Boolean[]
byrefModifiers, Int32 culture, String[] namedParameters)
at System.RuntimeType.InvokeMember(String name, BindingFlags bindingFlags, Binder binder, Object target, Object[] providedArgs,
ParameterModifier[] modifiers, CultureInfo culture, String[]
namedParams)
at System.Management.Automation.ComMethod.InvokeMethod(PSMethod method, Object[] arguments)
Update-Database : Exception has been thrown by the target of an invocation.
At line:1 char:1
+ update-database
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (Exception has b... an invocation.:String) [Update-Database], RuntimeException
+ FullyQualifiedErrorId : Exception has been thrown by the target of an invocation.,Update-Database
I tried cleaning the whole project , deleting ef and migration and packages folder and doing it from the beginning and still same error !
Anyone facing the same error? Or have a solution for this?
In case you have context and migration in separate projects, you need to use -StartupProjectName "YourProject" option of add-migration and update-database
The same error was in 4.3 beta. I encountered it in 4.3 release as well.
Instead of using the Powershell commands, you can control the migration via code, and then tell it where your assembly and context are:
var configuration = new DbMigrationsConfiguration() {
MigrationsAssembly = typeof(YourMigrations).Assembly,
ContextType = typeof(YourContext)
};
Then you can either script it out or auto-run it by using the DbMigrator class:
var migrator = new DbMigrator(configuration);
var scripter = new MigratorScriptingDecorator(migrator);
string script = scripter.ScriptUpdate(null, null);