So I tried implementing AdMob to my project but my ad is not showing up and I have no idea why.
I was following a guide online which I can't seem to find at this point but when they did it, it worked just fine, and I followed all the steps, I am starting to consider that it might be Xamarin but I am not sure.
I have a AdMobRenderer.cs that looks like this
using Google.MobileAds;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
namespace AdMobTestProject.iOS
{
public class AdMobRenderer : ViewRenderer
{
//hiding the key for this question
private const string adMobId = "ca-app-pub-xxxxxx/xxxxxxx";
private BannerView adView;
private bool viewOnScreen;
protected override void OnElementChanged(ElementChangedEventArgs<View> e)
{
base.OnElementChanged(e);
if (e.NewElement == null)
return;
if (e.OldElement == null)
{
adView = new BannerView(AdSizeCons.SmartBannerPortrait)
{
AdUnitID = adMobId,
RootViewController = UIApplication.SharedApplication.Windows[0].RootViewController
};
adView.AdReceived += (sender, args) =>
{
if (!viewOnScreen)
{
this.AddSubview(adView);
}
viewOnScreen = true;
};
Request request = Request.GetDefaultRequest();
adView.LoadRequest(request);
base.SetNativeControl(adView);
}
}
public AdMobRenderer()
{
}
}
}
And then the XAML aswell
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:AdMobTestProject"
x:Class="AdMobTestProject.MainPage">
<StackLayout>
<!-- Place new controls here -->
<Label Text="Welcome to Xamarin.Forms!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<local:AdMobView WidthRequest="320" HeightRequest="50"></local:AdMobView>
</StackLayout>
</ContentPage>
And ofcourse the MainPage.xaml.cs
namespace AdMobTestProject
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
}
public class AdMobView : ContentView
{
public AdMobView()
{
}
}
}
Am I missing something? Why is it not displaying anything when I deploy the app to my device? iPhone 7.
I am using Xamarin.Forms
Check the space available for the adview should not be less than 360 pixel wide so check the main layout of the page if there margins remove them.
as a clue check the build output window in visual studio it will show if the ads are loaded or not and show a reason for why ads are not visible if they are loaded.
in your sample remove the WidthRequest.
this is a late reply for future searches.
Try change adMobId to a test ad id.
https://developers.google.com/admob/android/test-ads
(ca-app-pub-3940256099942544/6300978111)
I had the same issue, and if I navigated to another page and went back my ads showed up.
Related
I am new to .Net Maui. I have follow James Montemagno's video tuorial:
https://www.youtube.com/watch?v=ddmZ6k1GIkM&list=PLdo4fOcmZ0oUBAdL2NwBpDs32zwGqb9DY&index=6 on navigating between pages. I can successfully navigate from one page to the next and also send a complex data object as a parameter. However, on the new page, I want to use the parameter to fetch objects via a webservice in my ViewModel, and bind the xaml to the newly fetched objects.
At first I tried this in the ViewModels' constructor, but the parameters where still null inside the constructor. I then invoked an event that fired when the property I am binding to changes partial void OnLoginResultChanged(LoginResult value). From there I call an async Task to fetch the objects from the webservice and try and bind and display them in the xaml. Unfortunately, I am not getting anything to show in the xaml.
Here is my code:
ViewModel:
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using MealPacApp.Model;
namespace MealPacApp.ViewModel
{
[QueryProperty(nameof(Model.LoginResult), "LoginResult")]
public partial class MainViewModel : ObservableObject
{
IConnectivity connectivity;
Services.MealPacService mealPacService;
[ObservableProperty]
Model.User user = new();
[ObservableProperty]
Model.LoginResult loginResult;
partial void OnLoginResultChanged(LoginResult value)
{
this.GetDataForViewCommand.ExecuteAsync(null);
}
public MainViewModel(IConnectivity connectivity, Services.MealPacService mealPacService)
{
this.connectivity = connectivity;
this.mealPacService = mealPacService;
//Now check to see if there is internet connectivity
if (connectivity.NetworkAccess != NetworkAccess.Internet)
{
Shell.Current.DisplayAlert("Oops!", "No internet is available. Please ensure you have an internet connection before continuing.", "OK");
return;
}
}
[RelayCommand]
async Task GetDataForView()
{
try
{
if (loginResult != null)
{
//Its not empty, so login here
var incmoingUser = await Services.MealPacService.GetUser(loginResult.Reference, loginResult.OrganisationId);
if (incmoingUser != null)
{
user = incmoingUser;
}
}
}
catch (Exception)
{
throw;
}
}
}
}
Here is the View (Xaml):
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MealPacApp.MainPage"
Title="Home"
xmlns:viewmodel="clr-namespace:MealPacApp.ViewModel"
xmlns:model="clr-namespace:MealPacApp.Model"
x:DataType="viewmodel:MainViewModel">
<ScrollView>
<VerticalStackLayout
Spacing="25"
Padding="30,0"
VerticalOptions="Center">
<Label
Text="{Binding User.Name}"
SemanticProperties.HeadingLevel="Level1"
FontSize="32"
HorizontalOptions="Center" />
</VerticalStackLayout>
</ScrollView>
</ContentPage>
Here is the Model I am trying to bind too:
namespace MealPacApp.Model
{
public partial class User
{
public int Userid { get; set; }
public string Reference { get; set; }
public string Name { get; set; }
}
}
Here is my page code behind:
using MealPacApp.ViewModel;
namespace MealPacApp
{
public partial class MainPage : ContentPage
{
public MainPage(MainViewModel vm)
{
InitializeComponent();
BindingContext = vm;
}
}
}
As mentioned, the navigation is working, I am just missing how to get the property change to reflect in the Xaml. I have kept the [ObservableProperty] instead of implementing INotifyPropertyChanged as to my understanding, it takes care of the boiler plate stuff.
Thanks in advance.
This line
user = incmoingUser;
Is updating the private field user
You want to update the public property User which is observable
User = incmoingUser;
I'm making an app which has a a ZXing ScannerView in a ContentPage.
I've managed to make it read a QR code just fine in a function in my ScanningViewModel.
However, when I try to navigate away from the page with the ScannerView, it crashes.
In the 'Application Output' in Visual Studio, I'm seeing a load of the 'Too soon between frames' error, which is I believe is causing the crashing. I've read that setting delays to 5 might help, but I'm not sure how to do this. This is where I read this: https://github.com/Redth/ZXing.Net.Mobile/issues/721
I've also seen some other StackOverflow articles, but they didn't really answer my question.
Is there a way to fix this?
Edit: This is the other post I read on StackOverflow:
Zxing Mobile doesn't stop analysing on iOS
XAML Page:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:zxing="clr-namespace:ZXing.Net.Mobile.Forms;assembly=ZXing.Net.Mobile.Forms"
xmlns:viewmodel1="clr-namespace:DoorRelease.ViewModel"
xmlns:viewmodel="clr-namespace:GardisMobileApp.ViewModel"
x:Class="GardisMobileApp.QRScanningPage">
<ContentPage.BindingContext>
<viewmodel:ScanningViewModel/>
</ContentPage.BindingContext>
<ContentPage.Content>
<StackLayout>
<StackLayout>
<Label Text="Welcome to Xamarin.Forms!"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
</StackLayout>
<zxing:ZXingScannerView x:Name="scanner" IsScanning="{Binding isScanning}" ScanResultCommand="{Binding GetResultCommand}" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
My Code Behind:
namespace MobileApp
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class QRScanningPage : ContentPage
{
public QRScanningPage()
{
InitializeComponent();
}
}
}
My ScanningViewModel:
namespace MobileApp.ViewModel
{
public class ScanningViewModel : BaseViewModel
{
private static ScanningViewModel _instance = new ScanningViewModel();
public static ScanningViewModel Instance { get { return _instance; } }
public string stsAddress { get; set; }
public string apiAddress { get; set; }
public bool isScanning { get; set; } = true;
public Command GetResultCommand { get; set; }
public ScanningViewModel() : base()
{
Title = "QR Code Scanner";
GetResultCommand = new Command(async(r) => await GetScannedAsync(r));
}
async Task GetScannedAsync(object result)
{
isScanning = false;
try
{
var resultArray = result.ToString().Split(',');
stsAddress = resultArray[0];
apiAddress = resultArray[1];
MainThread.BeginInvokeOnMainThread(async () =>
{
await Application.Current.MainPage.Navigation.PopAsync();
//await Application.Current.MainPage.DisplayAlert("Code scanned", "You've scanned a QR code!", "OK");
});
}
catch(Exception e)
{
await Application.Current.MainPage.DisplayAlert("Error!", e.Message, "OK");
}
}
}
}
From document INotifyPropertyChanged Interface,we know that
The INotifyPropertyChanged interface is used to notify clients, typically binding clients, that a property value has changed.
For change notification to occur in a binding between a bound client and a data source, your bound type should either:
Implement the INotifyPropertyChanged interface (preferred).
Provide a change event for each property of the bound type.
Do not do both.
In your code, if you want to update the UI while changing the value of isScanning , you have to inplement interface INotifyPropertyChanged .
public bool isScanning { get; set; } = true;
Please refer to the following code:
private bool _isScanning;
public bool isScanning
{
get
{
return _isScanning;
}
set
{
SetProperty(ref _isScanning, value);
}
}
And assign an initial value (true) for it in the constructor of class ScanningViewModel:
public ScanningViewModel()
{
//assign an initial value (`true`)
isScanning = true;
// other code
}
I know that this exact question has been asked hundreds of time, but every user has a different problem and I have already tried many solutions, not getting anywhere.
The good thing is that banner test ads (like the one here: LINK) are showing correctly… and I have registered a Unit banner in AdMob (without connecting FireBase, yet)
This is my code, taken from various samples in the internet… it's a pretty standard code pattern for everyone of them:
MainPage.xaml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:TestAd"
xmlns:localIOS="clr-namespace:TestAd.iOS"
xmlns:vm="clr-namespace:TestAd.ViewModels"
x:Class="TestAd.MainPage">
<ContentPage.BindingContext>
<vm:AppViewModel/>
</ContentPage.BindingContext>
<StackLayout>
<Grid …>
</Grid>
<localIOS:AdMobView AdUnitId="ca-app-pub-XXXXXXXXXXXXXXX/XXXXXXXXXX"/>
<ListView ...>
</ListView>
</StackLayout>
AdView
public class AdMobView : View
{
public static readonly BindableProperty AdUnitIdProperty = BindableProperty.Create(
nameof(AdUnitId),
typeof(string),
typeof(AdMobView),
string.Empty);
public string AdUnitId
{
get => (string)GetValue(AdUnitIdProperty);
set => SetValue(AdUnitIdProperty, value);
}
}
AdViewRenderer
[assembly: ExportRenderer(typeof(AdMobView), typeof(AdMobViewRenderer))]
namespace AppReminderIOS.iOS
{
public class AdMobViewRenderer : ViewRenderer<AdMobView, BannerView>
{
protected override void OnElementChanged(ElementChangedEventArgs<AdMobView> e)
{
base.OnElementChanged(e);
if (Control == null)
{
SetNativeControl(CreateBannerView());
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == nameof(BannerView.AdUnitID))
Control.AdUnitID = "ca-app-pub-XXXXXXXXXXXXXXXX/XXXXXXXXX"; //Even tried: "Element.AdUnitId;"
}
private BannerView CreateBannerView()
{
var bannerView = new BannerView(AdSizeCons.SmartBannerPortrait)
{
AdUnitID = "ca-app-pub-XXXXXXXXXXXXXXXXXX/XXXXXXXXX", //Even tried: "Element.AdUnitId,"
RootViewController = GetVisibleViewController()
};
bannerView.LoadRequest(GetRequest());
Request GetRequest()
{
var request = Request.GetDefaultRequest();
return request;
}
return bannerView;
}
private UIViewController GetVisibleViewController()
{
var windows = UIApplication.SharedApplication.Windows;
foreach (var window in windows)
{
if (window.RootViewController != null)
{
return window.RootViewController;
}
}
return null;
}
}
}
AppDelegate.cs
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
//
// This method is invoked when the application has loaded and is ready to run. In this
// method you should instantiate the window, load the UI into it and then make the window
// visible.
//
// You have 17 seconds to return from this method, or iOS will terminate your application.
//
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
Google.MobileAds.MobileAds.Configure("ca-app-pub-XXXXXXXXXXXXXXXXXX~XXXXXXXX");
Xamarin.Forms.Forms.Init();
LoadApplication(new App());
return base.FinishedLaunching(app, options);
}
}
This is the main code… what do you think?
Could there be a problem with my AdMob account?
Test ads are showing correctly AND they even refresh thereselves as I rotate the device… so I don't know what to think.
Thank you for you kindness in helping me.
If you have recently created an AD unit ID(in 24 hours), it may take some time and several AD requests to build up AD resources. Because of this, you may not immediately see the actual presentation. You should see more consistent results when your application requests multiple times. Please note that the test AD runs through the same channels as the actual AD. If the test AD returns, your application is communicating correctly with the network.
https://www.linkedin.com/pulse/xamarin-forms-contentpage-searchbar-navigation-bar-vipin-mathews/
I tried to implement the above code but not succeed, Search Icon not coming in page,
After that I tried this Adding a Search Bar in the toolbar of a navigationpage in Prism
, and its appears but once I changes the orientation or I logout or clicked on other page and come back again at this page its gone
I downloaded the code from git but not able to run that also.
<?xml version="1.0" encoding="utf-8" ?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="#+id/action_search"
android:title="Search"
android:icon="#android:drawable/ic_menu_search"
app:showAsAction="always|collapseActionView"
app:actionViewClass="android.support.v7.widget.SearchView"/>
</menu>
But ic_menu_search file not there in drawable folder, Is that an issue?
Just use the TitleView something like:
<NavigationPage.TitleView>
<StackLayout HorizontalOptions="FillAndExpand" Orientation="Horizontal">
<Label
HorizontalOptions="FillAndExpand"
Text="{StaticResource PageTitle}"
TextColor="White"
VerticalOptions="Center" />
<SearchBar
HorizontalOptions="End"
Placeholder="Search"
PlaceholderColor="{StaticResource GrayPlaceHolderColor}"
TextColor="White"
VerticalOptions="Center" />
</StackLayout>
</NavigationPage.TitleView>
We can create a custom renderer in both the Xamarin.iOS and Xamarin.Android to accomplish it.
Here's a sample application for reference:
https://github.com/brminnick/GitTrends
And here's a blog post that shows how to add a search bar to a Xamarin.Forms app for both Xamarin.iOS & Xamarin.Android: https://www.codetraveler.io/2019/08/10/adding-a-search-bar-to-xamarin-forms-navigationpage/
App.cs
Use a Xamarin.Forms Platform-Specific to use LargeTitles on the Xamarin.iOS app.
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
public class App : Xamarin.Forms.Application
{
public App()
{
var navigationPage = new Xamarin.Forms.NavigationPage(new MyContentPage());
navigationPage.On<iOS>().SetPrefersLargeTitles(true);
MainPage = navigationPage;
}
}
ISearchPage Interface
Create an Interface that can be used across the Xamarin.Forms, Xamarin.Android and Xamarin.iOS projects.
public interface ISearchPage
{
void OnSearchBarTextChanged(in string text);
event EventHandler<string> SearchBarTextChanged;
}
Xamarin.Forms Page
public class MyContentPage : ContentPage, ISearchPage
{
public MyContentPage()
{
SearchBarTextChanged += HandleSearchBarTextChanged
}
public event EventHandler<string> SearchBarTextChanged;
public void OnSearchBarTextChanged(in string text) => SearchBarTextChanged?.Invoke(this, text);
void HandleSearchBarTextChanged(object sender, string searchBarText)
{
//Logic to handle updated search bar text
}
}
iOS Custom Renderer
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UIKit;
using MyNamespace;
using MyNamespace.iOS;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(MyContentPage), typeof(SearchPageRenderer))]
namespace MyNamespace.iOS
{
public class SearchPageRenderer : PageRenderer, IUISearchResultsUpdating
{
bool _isFirstAppearing = true;
public override void WillMoveToParentViewController(UIViewController parent)
{
base.WillMoveToParentViewController(parent);
var searchController = new UISearchController(searchResultsController: null)
{
SearchResultsUpdater = this,
DimsBackgroundDuringPresentation = false,
HidesNavigationBarDuringPresentation = false,
HidesBottomBarWhenPushed = true
};
searchController.SearchBar.Placeholder = string.Empty;
parent.NavigationItem.SearchController = searchController;
DefinesPresentationContext = true;
}
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
//Work-around to ensure the SearchController appears when the page first appears https://stackoverflow.com/a/46313164/5953643
if (_isFirstAppearing)
{
ParentViewController.NavigationItem.SearchController.Active = true;
ParentViewController.NavigationItem.SearchController.Active = false;
_isFirstAppearing = false;
}
}
public void UpdateSearchResultsForSearchController(UISearchController searchController)
{
if (Element is ISearchPage searchPage)
searchPage.OnSearchBarTextChanged(searchController.SearchBar.Text);
}
}
}
Xamarin.Android Menu XML
In the Xamarin.Android project, in the Resources folder, create a new folder called menu (if one doesn't already exist).
Note: the folder, menu, has a lowercase 'm'
In the Resources > menu folder, create a new file called MainMenu.xml.
Open Resources > menu > MainMenu.xml
In MainMenu.xml add the following code:
<?xml version="1.0" encoding="utf-8" ?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="#+id/ActionSearch"
android:title="Filter"
android:icon="#android:drawable/ic_menu_search"
app:showAsAction="always|collapseActionView"
app:actionViewClass="android.support.v7.widget.SearchView"/>
</menu>
Xamarin.Android CustomRenderer
Uses the Plugin.CurrentActivity NuGet Package.
using Android.Content;
using Android.Runtime;
using Android.Support.V7.Widget;
using Android.Text;
using Android.Views.InputMethods;
using Plugin.CurrentActivity;
using MyNamespace;
using MyNamespace.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(MyContentPage), typeof(SearchPageRenderer))]
namespace MyNamespace.Droid
{
public class SearchPageRenderer : PageRenderer
{
public SearchPageRenderer(Context context) : base(context)
{
}
protected override void OnAttachedToWindow()
{
base.OnAttachedToWindow();
if (Application.Current.MainPage is NavigationPage navigationPage)
navigationPage.Popped += HandleNavigationPagePopped;
if (Element is ISearchPage && Element is Page page && page.Parent is NavigationPage navigationPage && navigationPage.CurrentPage is ISearchPage)
AddSearchToToolbar(page);
}
protected override void Dispose(bool disposing)
{
if (GetToolbar() is Toolbar toolBar)
toolBar.Menu?.RemoveItem(Resource.Menu.MainMenu);
base.Dispose(disposing);
}
void AddSearchToToolbar(in Page page)
{
if (GetToolbar() is Toolbar toolBar
&& toolBar.Menu?.FindItem(Resource.Id.ActionSearch)?.ActionView?.JavaCast<SearchView>().GetType() != typeof(SearchView))
{
toolBar.Title = page.Title;
toolBar.InflateMenu(Resource.Menu.MainMenu);
if (toolBar.Menu?.FindItem(Resource.Id.ActionSearch)?.ActionView?.JavaCast<SearchView>() is SearchView searchView)
{
searchView.QueryTextChange += HandleQueryTextChange;
searchView.ImeOptions = (int)ImeAction.Search;
searchView.InputType = (int)InputTypes.TextVariationFilter;
searchView.MaxWidth = int.MaxValue; //Set to full width - http://stackoverflow.com/questions/31456102/searchview-doesnt-expand-full-width
}
}
}
void HandleQueryTextChange(object sender, SearchView.QueryTextChangeEventArgs e)
{
if (Element is ISearchPage searchPage)
searchPage.OnSearchBarTextChanged(e.NewText);
}
void HandleNavigationPagePopped(object sender, NavigationEventArgs e)
{
if (sender is NavigationPage navigationPage
&& navigationPage.CurrentPage is ISearchPage)
{
AddSearchToToolbar(navigationPage.CurrentPage);
}
}
Toolbar GetToolbar() => CrossCurrentActivity.Current.Activity.FindViewById<Toolbar>(Resource.Id.toolbar);
}
}
Sample App
Here's a sample app for reference:
https://github.com/brminnick/GitTrends
And a blog post that shows how to add a search bar for both Xamarin.iOS and Xamarin.Android: https://www.codetraveler.io/2019/08/10/adding-a-search-bar-to-xamarin-forms-navigationpage/
Good afternoon everyone. I have just begun to work with Xamarin Forms as I will need it for my job and wanted to learn best practices from the beginning so I went for Mvvm Light. My current problem is that, whatever I do, I really can't make binding work (NOTE: it worked for my first project, a simple page where I had a button which was used to navigate to another page). Now, for my current project, an EventApp I tried everything I could, looking on lots of forums and tried various settings and implementations but couldn't make the binding work again. I will show you some of my current code for a test page I've done just for testing purposes.
App.cs class:
public partial class App : Application
{
private static ViewModelLocator _locator;
public static ViewModelLocator Locator { get { return _locator ?? (_locator = new ViewModelLocator()); } }
public App()
{
InitializeComponent() //Tried both with and without this
registerNavigationService();
}
protected override void OnStart()
{
}
protected override void OnSleep()
{
// Handle when your app sleeps
}
protected override void OnResume()
{
// Handle when your app resumes
}
public void registerNavigationService()
{
NavigationService nav = new NavigationService();
nav.Configure(PageNames.GeneralNotificationPage, typeof(GeneralNotificationPage));
nav.Configure(PageNames.CreateNotificationPage, typeof(CreateNotificationPage));
nav.Configure(PageNames.SelectSongPage,typeof(SelectSongPage));
SimpleIoc.Default.Register<INavigationService>(() => nav);
var firstPage = new NavigationPage(new SelectSongPage());
nav.Initialize(firstPage);
MainPage = firstPage;
}
}
`
App.xaml:
<?xml version="1.0" encoding="utf-8"?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="EventAppMvvm.App"
>
</Application>
-Note: here I tried to set a static resource for my ViewModelLocator the next way:
xlmns:vm="clr-namespace:EventAppMvvm.ViewModel;assembly=EventAppMvvm"
and then in resources
<vm:ViewModelLocator x:Key="Locator"/>
doesn't work, if I try in one of my pages to set the DataContext, it says it hasn't found any bindable property. If I set the BindingContext to that I get an NPE when I run the app as there is no object created. So I ended up using the code behind to do the BindingContext and instantiate the locator in my App.cs file so I won't receive an NPE.
ViewModelLocator:
public class ViewModelLocator
{
/// <summary>
/// Initializes a new instance of the ViewModelLocator class.
/// </summary>
public ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
////if (ViewModelBase.IsInDesignModeStatic)
////{
//// // Create design time view services and models
//// SimpleIoc.Default.Register<IDataService, DesignDataService>();
////}
////else
////{
//// // Create run time view services and models
//// SimpleIoc.Default.Register<IDataService, DataService>();
////}
SimpleIoc.Default.Register<CreateNotificationPageViewModel>();
SimpleIoc.Default.Register<SelectSongPageViewModel>();
SimpleIoc.Default.Register<GeneralNotificationPageViewModel>();
}
public CreateNotificationPageViewModel CreateNotificationPageVM
{
get
{
return ServiceLocator.Current.GetInstance<CreateNotificationPageViewModel>();
}
}
public SelectSongPageViewModel SelectSongPageVM
{
get
{
return ServiceLocator.Current.GetInstance<SelectSongPageViewModel>();
}
}
public GeneralNotificationPageViewModel GeneralNotificationPageVM
{
get
{
return ServiceLocator.Current.GetInstance<GeneralNotificationPageViewModel>();
}
}
public static void Cleanup()
{
// TODO Clear the ViewModels
}
}
One of my ViewModels(test one):
public class SelectSongPageViewModel : ViewModelBase
{
RelayCommand _commandTest;
Song _selectedSong;
INavigationService navigation;
string clicked = "3";
string _message = "I ve not been clicked yet";
public SelectSongPageViewModel(INavigationService navigation)
{
this.navigation = navigation;
}
RelayCommand CommandTest
{
get
{
if(_commandTest == null)
{
_commandTest= new RelayCommand(() =>
{
Message = _message;
//navigation.NavigateTo(PageNames.CreateEventPage);
});
}
return _commandTest;
}
}
public string Message
{
get
{
return clicked;
}
set
{
clicked = value;
RaisePropertyChanged("Message");
}
}
}
Actual page of that ViewModel:
Notes: if I try to use DataContext (defined as static resource previously in App.xaml), no matter if I give the correct namespace and assembly, it says that it hasn't found any binding, property there, if I use BindingContext, it works, I don't get any errors at compile time but I can't make the buttons do something as it is like it doesn't recognize my defined commands but for some reason it just binds simple data like my Message property.
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="EventAppMvvm.Views.SelectSongPage"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
>
<ContentPage.Content>
<StackLayout>
<Label Text="{Binding Message}"></Label>
<Button Text="Press me" Command="{Binding CommandTest}"></Button>
</StackLayout>
</ContentPage.Content>
</ContentPage>
And the code behind for this page.
namespace EventAppMvvm.Views
{
public partial class SelectSongPage : ContentPage
{
public SelectSongPage()
{
InitializeComponent();
var vm = App.Locator.SelectSongPageVM;
BindingContext = vm;
}
}
}
Whatever I do, I can't make the commands/Complex binding work again for some reason but still simple property binding works, I'm using VisualStudio for Mac if it matters.