How to work with IActivityLifecycleCallbacks with MVVMCross? - xamarin

I am new to MVVMCross. I need to get details about whether my android application is running in background or not. To achieve this i have try to implement with IActivityLifecycleCallbacks with MVXApplication.But i get following error "implements Android.Runtime.IJavaObject but does not inherit Java.Lang.Object or Java.Lang.Throwable. This is not supported.". So could anyone suggest me to how to achieve my requirement with MVVM cross.

You can implement that interface in your main application of your Android project and on the OnTrimMemory comparing the level with TrimMemory.UiHidden you can know if the app is in background or not.
public class MainApplication : Application, Application.IActivityLifecycleCallbacks
{
...
public static bool IsApplicationInForeground { get; private set; }
public override void OnCreate()
{
base.OnCreate();
this.RegisterActivityLifecycleCallbacks(this);
}
public override void OnTerminate()
{
base.OnTerminate();
this.UnregisterActivityLifecycleCallbacks(this);
}
public virtual void OnActivityResumed(Activity activity)
{
IsApplicationInForeground = true;
}
public override void OnTrimMemory(TrimMemory level)
{
IsApplicationInForeground &= level != TrimMemory.UiHidden;
base.OnTrimMemory(level);
}
...
}
IDK if it covers all of the cases but I use it in my projects and it works like a charm in the scenarios I've tested
HIH

Related

How to add a ViewModel for new pages of Xamarin Native iOS & Android apps

Context: I am handed this massive enterprise iOS & Android Xamarin Native applications that doesn't use ViewModels or any MVVM framework. It does have a separated Network services layer and it has a lot of pages, so starting over won't make any sense.
Why the change is needed: No MVVM, the services layer is called directly from the UI classes (Fragments & ViewControllers), and there is no good abstraction. So I will start with 1 view and then create TechDebt to transform the rest of the app.
What I know:
Adding MVVM frameworks require creating extensive changes, especially to use Navigation services for Navigating the views, and are best done if added when green-fielding the application.
As seen here, Android has an easy way of using a ViewModel but I won't be able to use that for iOS then.
I also know that I can launch a Xamarin Forms page instead and that will be all ready for MVVM, since I can just assign the BindingContext property to an instance of the ViewModel.
What I need: I need to create one new page for iOS & one for Android. I want to be able to create a ViewModel that's shared between iOS & Android. I want to be able to use it for a single view that I am creating and it should be initialized when the page is loaded.
How can I add 1 viewmodel that's shared by a ViewController & a Fragment? Am I missing something, is it much easier than I am making it?
Ended up being able to use MvvmLight for this. Added the Nuget package to the projects, Created a ViewModelBase in the Core Shared Library Project:
public abstract class ViewModelBase : GalaSoft.MvvmLight.ViewModelBase
{
private PropertyChangedEventHandler propertyChangedEventHandler;
protected bool IsLoading { get; set; }
public bool RegisteredPropertyEventHandler { get; set; }
public const string ErrorMessagePropertyName = "ErrorMessage";
public string ErrorMessage { get; set; }
public string SuccessMessage { get; set; }
public void RegisterPropertyEventHandler(PropertyChangedEventHandler propertyChangedEventHandler)
{
this.propertyChangedEventHandler = propertyChangedEventHandler;
this.PropertyChanged += propertyChangedEventHandler;
this.RegisteredPropertyEventHandler = true;
}
public void UnegisterPropertyEventHandler()
{
if (this.RegisteredPropertyEventHandler)
{
this.PropertyChanged -= propertyChangedEventHandler;
this.RegisteredPropertyEventHandler = false;
this.propertyChangedEventHandler = null;
}
}
public void TearDown()
{
this.UnegisterPropertyEventHandler();
}
protected void NotifyError (string message)
{
this.ErrorMessage = message;
RaisePropertyChanged (() => ErrorMessage);
}
}
and a ViewModelLocator
public class ViewModelLocator
{
public const string ABCPageKey = "ABCPage";
public ABCViewModel ABC
{
get
{
return ServiceLocator.Current.GetInstance<ABCViewModel> ();
}
}
public ViewModelLocator ()
{
ServiceLocator.SetLocatorProvider (() => SimpleIoc.Default);
// Register all of the view models
SimpleIoc.Default.Register<ABCViewModel> ();
}
public static void Cleanup ()
{
}
public T GetViewModel<T> ()
{
return ServiceLocator.Current.GetInstance<T> ();
}
}
On the iOS side, I already had a BaseUIViewController, so I created a BaseViewModelUIViewController on top of it
public abstract partial class BaseViewModelUIViewController<T> : BaseUIViewController where T : ViewModelBase
{
public T ViewModel
{
get
{
return App.Locator.GetViewModel<T> ();
}
}
public BaseViewModelUIViewController (IntPtr handle) : base (handle)
{
}
internal virtual void ViewModelPropertyChangedHandler (object sender, PropertyChangedEventArgs e)
{
Console.WriteLine (string.Format ("****** Property Changed for {0} in {1}", e.PropertyName, this.GetType ().Name));
switch (e.PropertyName)
{
default:
break;
}
}
}
And then Android, similarly I already had a BaseFragment, so I created a BaseViewModelFragment on top of it
public class BaseViewModelFragment<T> : BaseFragment where T : ViewModelBase
{
public T ViewModel
{
get
{
return App.Locator.GetViewModel<T> ();
}
}
public BaseViewModelFragment (string title) : base (title)
{
}
internal virtual void ViewModelPropertyChangedHandler (object sender, PropertyChangedEventArgs e)
{
Console.WriteLine (string.Format ("****** Property Changed for {0} in {1}", e.PropertyName, this.GetType ().Name));
switch (e.PropertyName)
{
default:
break;
}
}
public override void OnDestroyView ()
{
this.ViewModel.TearDown ();
base.OnDestroyView ();
}
}
I hope it makes sense to other people looking for solutions.
Creating ViewModels: So naturally, for every new ViewModel created, I had to register it in the ViewModelLocator.
Using ViewModels: In terms of usage, you can simply use the ViewModel in the UI by inheriting from the ": BaseViewModelUIViewController" for iOS or from ": BaseViewModelFragment" for Android
Unfortunately you don't miss anything, all your claims are proper and you have properly listed various directions that you can take (and that you don't like).
Xamarin.Android and Xamarin.iOS are not made with data binding in mind, but rather with using the native interfaces, only Xamarin.Forms is made for the data binding. The capabilities of native platforms to use the data binding is limited (if it existed it would be incompatible among the platforms and you would have to make separate view models, and there is not data binding for iOS as of now anyway).
So basically there is no data binding in Xamarin.iOS and Xamarin.Android. It is completely up to you to abstract the shared business model and connect it with the user interface.

Using FluentScheduler - ASP.NET Core MVC

I currently have a simple website setup with ASP.NET Core MVC (.NET 4.6.1), and I would like to periodically do some processes like automatically send emails at the end of every day to the registered members.
After doing some searching, I came across two common solutions - Quartz.NET and FluentScheduler.
Based on this SO thread, I found the approach of using FluentScheduler more easier to digest and use for my simple task. After quickly implementing the following lines of code into my Program.cs class, I had the emails going out successfully every minute (for testing purposes).
public class Program
{
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
var registry = new Registry();
JobManager.Initialize(registry);
JobManager.AddJob(() => MyEmailService.SendEmail(), s => s
.ToRunEvery(1)
.Minutes());
host.Run();
}
}
However, now apart from sending emails I also need to do some back-end processing for e.g. updating the user records in the DB when mails are being sent out. For this, I normally inject my Entity Framework Context into the constructor of my controllers and use it to get/update SQL records.
My question is, since I cannot really inject these services into the main method, where would be the appropriate place to initialize the registry and add jobs for scheduling?
Thanks for the help, I am a little new to this so a little guidance would be much appreciated!
Instead of Program's Main function, I initialized the same in Startup.cs before app.UseMvc..
public void Configure(...., IDependencyObject dependencyObject)
{
....
JobManager.Initialize(new MyRegistry(dependencyObject));
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "api/{controller}/{action}/{id?}");
});
}
My registry class looks like this:
public class MyRegistry: Registry
{
public MyRegistry(IDependencyObject dependencyObject)
{
Schedule(() => new SyncUpJob(dependencyObject)).ToRunNow().AndEvery(10).Seconds();
}
}
My Job class looks like this:
public class SyncUpJob: IJob
{
public SyncUpJob(IDependencyObject dependencyObject)
{
DependencyObject= dependencyObject;
}
public IDependencyObject DependencyObject{ get; set; }
public void Execute()
{
// call the method to run weekly here
}
}
You can define all your jobs and their schedules, by subclassing from FluentScheduler Registry class. something like:
public class JobRegistry : Registry {
public JobRegistry() {
Schedule<EmailJob>().ToRunEvery(1).Days();
Schedule<SomeOtherJob>().ToRunEvery(1).Seconds();
}
}
public class EmailJob : IJob {
public DbContext Context { get; } // we need this dependency, right?!
public EmailJob(DbContext context) //constructor injection
{
Context = context;
}
public void Execute()
{
//Job implementation code: send emails to users and update database
}
}
For injecting dependencies into jobs, you need to implement FluentScheduler IJobFactory interface. GetJobIntance method is called by FluentScheduler for creating job instances. Here you can use any DI library you want; In this sample implementation, I'm going to assume that you use Ninject:
public class MyNinjectModule : NinjectModule {
public override void Load()
{
Bind<DbContext>().To<MyDbContextImplemenation>();
}
}
public class JobFactory : IJobFactory {
private IKernel Kernel { get; }
public JobFactory(IKernel kernel)
{
Kernel = kernel;
}
public IJob GetJobInstance<T>() where T : IJob
{
return Kernel.Get<T>();
}
}
Now you can start your jobs in main method by calling:
JobManager.JobFactory = new JobFactory(new StandardKernel(new MyNinjectModule()));
JobManager.Initialize(new JobRegistry());

How to detect when MvxListView is bound and has loaded its bindings?

I've Inherted MvxListView to my CustomMvxListView where I dos something with the visualization when a child has been added or removed.
It works great but can be laggy when many items get bound.
Is there a way to detect when Mvx view controls are bound and loaded there first bound data?
Found a good solution myself;
To track Itemsource changes in Android in a ListView you can use a DataSetObserver.
like:
internal class MyObserver : DataSetObserver
{
private readonly object view;
public MvxListViewNonScrollableObserver(ViewToTrack view)
{
tView = view;
DoSomething():
}
public override void OnChanged()
{
base.OnChanged();
DoSomething():
}
}
Add it to a ListView by:
class MyMvxListView : MvxListView
{
protected override void OnAttachedToWindow()
{
base.OnAttachedToWindow();
itemsourceObserver = new MyObserver(this);
Adapter.RegisterDataSetObserver(itemsourceObserver);
}
protected override void OnDetachedFromWindow()
{
if (itemsourceObserver != null)
{
Adapter.UnregisterDataSetObserver(itemsourceObserver);
itemsourceObserver = null;
}
base.OnDetachedFromWindow();
}
public void DoSomething()
{
}
DoSomething() get raised after load and on every itemsource change.

Autofac with MEF integration

I need help. I create Windows Service with Autofac container.
And I use MEF Integration service for create several alternative components for my service.
For example:
Module 1
[Export(typeof(IClass1))]
public class Class1 : IClass1
{
public void Show()
{
Console.WriteLine("Hallo from Class1");
}
}
Module 2
[Export(typeof(IClass2))]
public class Class2 : IClass2
{
public void Show()
{
Console.WriteLine("Hallo from Class2");
}
}
Basic class for modules integration - example
class Program
{
private static IContainer Container { get; set; }
static void Main(string[] args)
{
// Create your builder.
var builder = new ContainerBuilder();
/** find all modules in selected folder */
var catalog = new DirectoryCatalog(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + #"\modules", "*Module.dll");
/** register finded modules */
builder.RegisterComposablePartCatalog(catalog);
builder.RegisterType<MyClass>().As<IMyClass>().SingleInstance();
Container = builder.Build();
var cls = Container.Resolve<IMyClass>();
cls.Show();
Console.WriteLine("Class ready. Press Enter");
Console.ReadKey(true);
}
}
class MyClass: IMyClass
{
private readonly IClass1 _class1;
private readonly IClass1 _class3;
private readonly IClass2 _class2;
private readonly IClass2 _class4;
public MyClass(IClass1 class1, IClass2 class2)
{
_class1 = class1;
_class2 = class2;
_class3 = class1;
_class4 = class2;
}
public void Show()
{
_class1.Show();
Console.WriteLine("Class1 ready. Press Enter");
Console.ReadKey(true);
_class2.Show();
Console.WriteLine("Class1 ready. Press Enter");
Console.ReadKey(true);
}
}
internal interface IMyClass
{
void Show();
}
In this example all work fine.This principle I use in my service. For test start and debug my service I use Service.Helper from Nuget packages repository.
Everithyng work fine too.
But. If i create install package in Advance installer and install my service in system (Windows 8.1 x64) service do not start.
Logging exception from service write System.ArgumentNullException in system Event log. Exception most likely in this line
builder.RegisterComposablePartCatalog(catalog);
Service do not load any modules from start folder. Access denied from service to his subfolder. Help please. Thanks.
Try Assembly.GetEntryAssembly().Location insted of Assembly.GetExecutingAssembly().Location

How to Integrate Prism, Unity, and Enterprise Library

I'm building a WPF application. I'm using Prism 4, and Unity. I want to add two Enterprise Library 5 blocks to the application, Logging and Exception Handling. I have a singleton LoggerFacadeCustom.cs in my Infrastructure class that supports the ILoggerFacade and I've created it in my bootstrapper, and it is generating log files. It "news" up a unity container in its constructor (second code block)
Where do I add the container.resolve for ExceptionManager? How do I connect the Exception handling block to ILoggerFacade in my bootstrapper? How do I get all the exceptions to come out in the same log? Here is my existing bootstrapper.cs
public class Bootstrapper : UnityBootstrapper {
protected override ILoggerFacade CreateLogger() {
return LoggerFacadeCustom.Instance;
}
protected override DependencyObject CreateShell() {
return Container.Resolve<Shell>();
}
protected override void InitializeShell() {
base.InitializeShell();
App.Current.MainWindow = (Window)Shell;
App.Current.MainWindow.Show();
//Other shell stuff...
}
protected override IModuleCatalog CreateModuleCatalog() {
var catalog = new ModuleCatalog();
//These primary modules must register their own services as if they were acting independantly
catalog.AddModule(typeof(XmlCommentMergeModule));
//These support modules require at least one primary module above to be added first
catalog.AddModule(typeof(ToolboxHeaderModule));
catalog.AddModule(typeof(ToolboxFooterModule));
catalog.AddModule(typeof(ToolboxStartModule));
return catalog;
}
}
LoggerFacadeCustom:
public class LoggerFacadeCustom : ILoggerFacade {
private static readonly LoggerFacadeCustom _instance = new LoggerFacadeCustom();
public static LoggerFacadeCustom Instance { get { return _instance; } }
private LoggerFacadeCustom() {
var container = new UnityContainer();
container.AddNewExtension<EnterpriseLibraryCoreExtension>();
_logWriter = container.Resolve<LogWriter>();
}
private readonly LogWriter _logWriter;
public void Write(string message) { Write(message, null); }
public void Write(string message, string category, int priority) {
_logWriter.Write(message, category, priority);
}
public void Write(string message, Dictionary<string, object> properties) {
_logWriter.Write(message, LiteralString.LogCategoryProcess, properties);
}
#region ILoggerFacade Members
public void Log(string message, Category category, Priority priority) {
throw new NotImplementedException();
}
#endregion
}
Your bootstrapper is the Composition Root of your application. You should register all dependencies there. And only there. You should never reference the container directly outside the composition root.
If your classes have a dependency you should inject that dependency using a pattern like constructor injection.
Don't use static classes. Static kills dependency injection and testability and it hides dependencies to a point where everything is referenced from everywhere.
Make your logger facade a constructor parameter. You can do the same with the error handling block.
Don't use the container as a ServiceLocator. That is considered an anti-pattern in modern software architecture.

Resources