I am working on a Xamarin.Android project (Not Xamnarin.Forms). All the tutorials i see are for Xamarin.Froms. I am unable to find anything which explains how to use MVVM pattern for Xamarin.Android project.
In my MainAcitity.cs I Dont have the SetBindingContext/DataContext methods, I am not really sure how can i Bind my ViewModel to my UI.
my VM
internal class MainVM : ViewModelBase
{
private readonly DelegateCommand _BtnRegister;
public ICommand BtnRegister { get; set; }
public MainVM()
{
_BtnRegister = new DelegateCommand(onRegisterClick);
}
private void onRegisterClick(object commandParameter)
{
}
}
and here is my Activity File
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.activity_main);
}
how do i Bind my VM to my Activity?
Related
Why when I try to set ActionBar.CustomView.SetBackgroundColor (Color.White); Does the application crash?
I tried installing the ToolbarItems background via style, toolbar.axml via ResourceDictionary but not one of these methods works for me - I think because I'm too dumb.
Now this option is the easiest for me, since there is only one line of code, but somewhere you can see the conflict comes from style or toolbar.axml or something else.
ActionBar.CustomView.SetBackgroundColor (Color.White);
my app.xaml.cs
using System;
using System.IO;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using MyApp1.Services;
using MyApp1.Views;
namespace MyApp1
{
public partial class App : Application
{
static Data.TodoItemDatabase database;
public App()
{
InitializeComponent();
MainPage = new AppShell();
}
protected override void OnStart()
{
// Handle when your app start
}
protected override void OnSleep()
{
// Handle when your app sleeps
}
protected override void OnResume()
{
// Handle when your app resumes
}
public static Data.TodoItemDatabase Database
{
get
{
if (database == null)
{
database = new Data.TodoItemDatabase(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "TodoSQLite.db3"));
}
return database;
}
}
public int ResumeAtTodoId { get; set; }
}
}
Solution 1:
You can set the style of TitleView in Forms . You can create a base Navigation Pageand set the style of TitleView
<NavigationPage.TitleView>
<StackLayout Orientation="Horizontal" BackgroundColor="White" >
//...
</StackLayout>
</NavigationPage.TitleView>
Solution 2
You can try creating a Custom Renderer and set it as the base class for all pages in the app. Within this custom renderer you can try to set the background color and other style as you want in CustomTitleView .
[assembly: ExportRenderer(typeof(Page), typeof(AndroidNavigationPageRenderer )]
public class AndroidNavigationPageRenderer : PageRenderer
{
private CustomTitleView _titleView;
public NavigationSearchRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
{
base.OnElementChanged(e);
var activity = this.Context as FormsAppCompatActivity;
if (activity == null)
return;
var toolbar = activity.FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar);
_titleView= new TitleView(Context);
toolbar.AddView(_titleView);
}
}
I am getting a message saying FormsContext is obsolete. I saw numerous suggestions on how to fix it but none apply to my case below:
[assembly: Xamarin.Forms.Dependency(typeof(SoundMethods))]
namespace J.Droid
{
public class SoundMethods : ISoundMethods
{
public void IsDeviceSilent()
{
AudioManager am = (AudioManager)Forms.Context.GetSystemService(Context.AudioService);
}
}
}
Can anyone suggest how I can fix this for my example?
I usually use the Plugin.CurrentActivity from James Montemagno.
Nuget: https://www.nuget.org/packages/Plugin.CurrentActivity
Github: https://github.com/jamesmontemagno/CurrentActivityPlugin
You have to initialize the plugin in your AppDelegate OnCreate:
CrossCurrentActivity.Current.Init(this, bundle);
Then in your services (or in any class in the Android Project) you can get the current context with this:
var context = CrossCurrentActivity.Current.AppContext
You can get the context in your constructor like this:
private Context _context;
public ContentPageRenderer(Context context) : base(context)
{
_context = context;
}
And then access it with the _context variable.
You can add a method to init and pass the Context from the MainActivity:
static Context _context;
public static void Init(Context context)
{
_context = context;
}
public void IsDeviceSilent()
{
AudioManager am = (AudioManager)_context.GetSystemService(Context.AudioService);
}
then, in MainActivity
SoundMethods.Init(this);
You can read more about in here
I have a strange issue of getting null exception. I created class that implements ICommand interface, I have two methods.
public void Execute(object parameter)
{
NavigateAsync();
}
private async void NavigateAsync()
{
await App.MainNavigation.PushAsync(new Pages.SettingsPage());
}
When NavigateAsync() is exectude my MainNavigation is always null, even that I can see that parameter inside Execute is set.
In my App.xaml.cs file I have created public static INavigation MainNavigation { get; set; }
public partial class App : Application
{
public static ViewModels.MainViewModel ViewModel { get; set; }
public static INavigation MainNavigation { get; set; }
public App ()
{
InitializeComponent();
MainPage = new NavigationPage(new Paperboy.MainPage());
}
protected override void OnStart ()
{
// Handle when your app starts
}
protected override void OnSleep ()
{
// Handle when your app sleeps
}
protected override void OnResume ()
{
// Handle when your app resumes
}
}
Se when clicking icon i can se that command is executed but App.MainNavigation inside NavigateAsync() in null. So command is not executing PushAsync to SettingsPage.
You never instantiate your static MainNavigation property...
If I can give you 2 remarks:
instead of using a static property declared into your App.xaml.cs, maybe a better implementation could be to embed a Navigation getter into a specific 'service' class or directly into your Command definition:
public class MyCommand : ICommand
{
...
// Navigation getter
// There are better places for this prop but it's better
// than in app.xaml.cs
private INavigation MainNavigation
{
get => Application.Current?.MainPage?.Navigation;
}
public void Execute(object parameter)
{
NavigateAsync();
}
private async void NavigateAsync()
{
try
{
await MainNavigation?.PushAsync(new Pages.SettingsPage());
}
catch(){ ... }
}
}
Another point I would like to note, is that your Command looks like asynchronous. Maybe you already know, but here is a good implementation of async commands to avoid app crashes: Asynchronous commands
I hope it can help you. Happy coding !
I develop a Custom Plugin of MvvmCross for Windows Phone 8.1 and iOS
Its loading in iOS project but giving error in Windows Phone 8.1 at the manager.EnsurePlatformAdaptionLoaded();
public class PluginLoader : IMvxPluginLoader
{
public static readonly PluginLoader Instance = new PluginLoader();
public void EnsureLoaded()
{
var manager = Mvx.Resolve<IMvxPluginManager>();
manager.EnsurePlatformAdaptionLoaded<PluginLoader>();
}
}
Error is
An exception of type 'Cirrious.CrossCore.Exceptions.MvxException'
occurred in Cirrious.CrossCore.DLL but was not handled in user code
Additional information: could not load plugin assembly for type
Confiz.MvvmCross.Plugins.Timer.PluginLoader
I am loading my Plugin in Windows Phone 8.1 using the following code
public class TimerPluginBootstrap : MvxPluginBootstrapAction<Confiz.MvvmCross.Plugins.Timer.PluginLoader>
{
}
I am Using Windows Phone 8.1 and MvvmCross 3.2.1 and Following are the more info
Confiz.MvvmCross.Plugins.Timer(Portable)
ITimer.cs
public interface ITimer
{
void Start();
void Stop();
Action CallBackMethod { get; set; }
}
PluginLoader.cs
public class PluginLoader : IMvxPluginLoader
{
public static readonly PluginLoader Instance = new PluginLoader();
public void EnsureLoaded()
{
var manager = Mvx.Resolve<IMvxPluginManager>();
manager.EnsurePlatformAdaptionLoaded<PluginLoader>();
}
}
Confiz.MvvmCross.Plugins.Timer.WindowsPhone
MvxWindowsPhoneTimer.cs
public class MvxWindowsPhoneTimer : ITimer
{
private readonly DispatcherTimer timer;
public MvxWindowsPhoneTimer(double kronosApiRecallTimeInMinutes)
{
timer = new DispatcherTimer();
Timer.Interval = TimeSpan.FromSeconds(kronosApiRecallTimeInMinutes);
Timer.Tick += Timer_Tick;
}
void Timer_Tick(object sender, object e)
{
CallBackMethod.Invoke();
}
public DispatcherTimer Timer
{
get { return timer; }
}
public void Start()
{
Timer.Start();
}
public void Stop()
{
Timer.Stop();
}
public Action CallBackMethod { get; set; }
}
Plugin.cs
public class Plugin : IMvxPlugin
{
public void Load()
{
Mvx.RegisterSingleton<ITimer>(new MvxWindowsPhoneTimer(1));
}
}
The plugin extension name for Silverlight is WindowsPhone
For Jupiter Xaml Windows Phone apps, the extension name is WindowsCommon (if shared with Win81) and WindowsPhoneStore for Store only.
So Confiz.MvvmCross.Plugins.Timer.WindowsPhone.dll is for Silverlight
And Confiz.MvvmCross.Plugins.Timer.WindowsPhoneStore.dll is for Jupiter Xaml apps
I am using MVVM in one of the app. I have created different project for Model, View and View Model.
I need to navigate to another XAML from ViewModel. I found some solution using MVVM light. Is there any way of implementing navigation from view model without using MVVM light.
Simple as that,
IF you want to navigate from page1 to page2,
private void MoveToPage2FromPage1()
{
NavigationService.Navigate(new Uri("/Page2.xaml", UriKind.Relative));
}
How to perform page navigation on Windows Phone 8
You can store current page url on a notify property of Shared ViewModel in App. After that, it is easy to catch the change of this url and navigate to the correct url by observing it.
public class AppViewModel : INotifyPropertyChanged
{
public string CurrentPageURL { get; set; }
private string _currentPageURL;
public string CurrentPageURL
{
get { return _currentPageURL;}
set
{
if (_currentPageURL==value)
return; // to prevent reload the same page.
_currentPageURL = value;
NotifyPropertyChangedCurrentPageURL
}
}
// INotifyPropertyChanged implementations
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
// Store in static singleton instance of AppViewModel
public class App : Application
{
private static Lazy<AppViewModel> _ViewModel=new Lazy<ViewModel>();
public static AppViewModel ViewModel { get { return _ViewModel.Value; } }
....
public App()
{
AppViewModel.PropertyChanged=(s,a) =>
{
if (a.PropertyName=="CurrentPageURL")
{
NavigationService.Navigate(new Uri(AppViewModel.CurrentPageURL, UriKind.Relative));
};
}
}
}
// Usage sample
public class Page1ViewModel
{
private btnMoveNextPage_Click(object s, EventHandler a) {
App.ViewModel.CurrentURL="~/Page2.xaml";
}
}