Using IPageDialogService in OnNavigatedTo on app startup - xamarin.forms

I've created a Prism Unity App using the Prism Template Pack and added another View and ViewModel (OtherPage and OtherPageViewModel) to it. This is my code:
App.xaml.cs
public partial class App : PrismApplication
{
public App(IPlatformInitializer initializer = null) : base(initializer) { }
protected override void OnInitialized()
{
InitializeComponent();
NavigationService.NavigateAsync("MainPage?title=Hello%20from%20Xamarin.Forms");
}
protected override void RegisterTypes()
{
Container.RegisterTypeForNavigation<MainPage>();
Container.RegisterTypeForNavigation<OtherPage>();
}
}
MainPageViewModel.cs
public class MainPageViewModel : BindableBase, INavigationAware
{
private INavigationService _navigationService;
private IPageDialogService _pageDialogService;
public DelegateCommand NavigateToOtherPageCommand { get; set; }
private string _title;
public string Title
{
get { return _title; }
set { SetProperty(ref _title, value); }
}
public MainPageViewModel(INavigationService navigationService,
IPageDialogService pageDialogService)
{
_navigationService = navigationService;
_pageDialogService = pageDialogService;
NavigateToOtherPageCommand = new DelegateCommand(async () => await NavigateToOtherPage());
}
public void OnNavigatedFrom(NavigationParameters parameters)
{
}
public async void OnNavigatedTo(NavigationParameters parameters)
{
if (parameters.ContainsKey("title"))
Title = (string)parameters["title"] + " and Prism";
await _pageDialogService.DisplayAlertAsync("Message", "Message for the user", "Ok");
}
private async Task NavigateToOtherPage()
{
await _navigationService.NavigateAsync("OtherPage");
}
}
OtherPageViewModel.cs
public class OtherPageViewModel : BindableBase, INavigationAware
{
private IPageDialogService _pageDialogService;
public OtherPageViewModel(IPageDialogService pageDialogService)
{
_pageDialogService = pageDialogService;
}
public void OnNavigatedFrom(NavigationParameters parameters)
{
}
public async void OnNavigatedTo(NavigationParameters parameters)
{
await _pageDialogService.DisplayAlertAsync("Message", "Message for the user", "Ok");
}
}
I'm attempting to use the IPageDialogService to display a message to the user in the MainPageViewModels's OnNavigatedTo method but no message is displayed and no error is raised.
However, if I navigate from MainPage to OtherPage using the NavigateToOtherPageCommand, the message is displayed correctly. Why doesn't the IPageDialogService work in the OnNavigatedTo method of the startup page (i.e MainPageViewModel)? It seems to work fine in the OnNavigatedTo method of any other page (i.e OtherPageViewModel).

Try to use await Task.Yield(). More information about this issue in this link: pageDialogService MainPage reference is always null inside OnNavigatedTo after app is launched

Related

InvalidOperationException: Unable to resolve service for type with EF dbcontext

I am trying to use Dependency Injection for DB context. I am not sure what i am doing wrong but even after following all the steps i still get the error
Below are the steps that i follow ,suggest me where its going wrong. I am using multi tier project hence my repositories are in my DB access layer and controller in a mvc api application
My DB Context class
public partial class TestDbContext: DbContext
{
public TestDbContext(DbContextOptions<TestDbContext> options)
: base(options)
{
}
public virtual DbSet<Table1> Table1{ get; set; }
}
public interface IRepository<T> where T : class
{
IQueryable<T> GetDbSet();
}
public class Repository<T> : IRepository<T> where T : class
{
protected DbContext _entities;
protected readonly DbSet<T> _dbset;
public Repository(DbContext context)
{
_entities = context;
_dbset = context.Set<T>();
}
public virtual IQueryable<T> GetDbSet()
{
return _dbset;
}
}
pulbic interface IUserRepository
{
List<UsersInfo> GetUsers();
}
public class UserRepository:IUserRepository
{
private readonly IRepository<Table1> table1repo;
public UserRepository(IRepository<Table1> _table1Repo)
{
table1repo = _table1Repo;
}
public List<UsersInfo> GetUsers()
{
return table1repo.GetDbSet().ToList();
}
}
public class MyController : : ControllerBase
{
private readonly IUserRepository _UserRepo;
public MyController (IUserRepository UserRepo)
{
_UserRepo= clientInfo;
}
[HttpGet]
public async Task<IActionResult> Get()
{
try
{
var result = _UserRepo.GetUsers();
return new JsonResult(result) { SerializerSettings = new JsonSerializerSettings() { Formatting = Formatting.Indented } };
}
catch(Exception e)
{
throw e;
}
}
}
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IConfiguration>(Configuration);
services.Configure<IISOptions>(options =>
{
options.AutomaticAuthentication = false;
});
services.AddDbContext<TestDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("ConnectionString")));
services.AddScoped<IUserRepository, UserRepository>();
services.AddScoped(typeof(IRepository<>), typeof(Repository<>));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
Your context type in your repository class should be TestDbContext instead of DbContext.
public class Repository<T> : IRepository<T> where T : class
{
protected TestDbContext _entities;
protected readonly DbSet<T> _dbset;
public Repository(TestDbContext context)
{
_entities = context;
_dbset = context.Set<T>();
}
public virtual IQueryable<T> GetDbSet()
{
return _dbset;
}
}

Xamarin Forms:Prism:Android:MainActivity: Click on Push Notifications: PushAsync not supported globally on Android, please use a NavigationPage

I am trying to implement a basic push notification example using
Xamarin Forms with Prism MVVM, Azure & FCM.
I am receiving notification, but couldn't navigate to a specific page when clicked on the notification.
Trying basic functionality when the app is running or in the background (not closed).
It's throwing an exception "PushAsync not supported globally on Android, please use a NavigationPage" at
ExploreXam.App.Current.MainPage.Navigation.PushAsync(page);
[Activity(LaunchMode = LaunchMode.SingleTask, MainLauncher = true]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
internal static readonly string CHANNEL_ID = "explore_xamarin";
internal static readonly int NOTIFICATION_ID = 1029;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
CreateNotificationChannel();
global::Xamarin.Forms.Forms.Init(this, bundle);
LoadApplication(new App());
}
protected override void OnNewIntent(Intent intent)
{
base.OnNewIntent(intent);
Intent = intent;
NotificationClickedOn(intent);
}
private void NotificationClickedOn(Intent intent)
{
if (intent.Action == ExploreXamFirebaseMessagingService.ExploreXamNotification && intent.HasExtra("XamId"))
{
var page = new Xamarin.Forms.NavigationPage(new SpecificPage());
Xamarin.Forms.Application.Current.MainPage.Navigation.PushAsync(page);
ExploreXam.App.Current.MainPage.Navigation.PushAsync(page);
}
}
}
public partial class App : PrismApplication
{
public bool navigating;
public App(IPlatformInitializer initializer = null, bool shallNavigate=false) : base(initializer)
{
navigating = shallNavigate;
}
protected async override void OnInitialized()
{
BlobCache.ApplicationName = "ExploreXam";
InitializeComponent();
FlowListView.Init();
//await NavigationService.NavigateAsync("LoginPage");
await NavigationService.NavigateAsync("NavigationPage/LoginPage");
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
//mapping
}
}
Any idea that would help out, please?
You could access Prims's NavigationService instance to achieve what you're trying to do. But, it's a protected property. So, first you'd have to expose it through your App class as below :
public new INavigationService NavigationService => base.NavigationService;
Now, you can access the NavigationService from anywhere in your app by simply referencing it through your App as below:
(Xamarin.Forms.Application.Current as App).NavigationService.NavigateAsync("your/page/path");
So, your App class would look something like this:
public partial class App : PrismApplication
{
public new INavigationService NavigationService => base.NavigationService;
public bool navigating;
public App(IPlatformInitializer initializer = null, bool shallNavigate=false) : base(initializer)
{
navigating = shallNavigate;
}
protected async override void OnInitialized()
{
BlobCache.ApplicationName = "ExploreXam";
InitializeComponent();
FlowListView.Init();
//await NavigationService.NavigateAsync("LoginPage");
await NavigationService.NavigateAsync("NavigationPage/LoginPage");
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
//mapping
}
}
And your NotificationClickOn function would become something like :
private async void NotificationClickedOn(Intent intent)
{
if (intent.Action == ExploreXamFirebaseMessagingService.ExploreXamNotification && intent.HasExtra("XamId"))
{
var navigationService = (Xamarin.Forms.Application.Current as ContosoCookbook.App).NavigationService;
await navigationService.NavigateAsync("YourNavigationPage/SpecificPage");
}
}
The reason this is happening is because your Application.Current.MainPage is not a Navigation page but a ContentPage (i assume)
Wrap your initial MainPage in a NavigationPage as show below and it should work
In your App.xaml.cs
MainPage= new NavigationPage(new FirstPage());
I agree with #chaosifier. Create a public INavigationService in your App.xaml.cs file and then in the OnInitialized() method make the public property = the the base.NavigationService;
public INavigationService PrismNavigation { get; private set; }
protected override async void OnInitialized()
{
InitializeComponent();
PrismNavigation = base.NavigationService;
}
Then from the MainActivity.cs file you can navigate using something like this
(Xamarin.Forms.Application.Current as App).PrismNavigation.NavigateAsync(nameof(ShowAlertsDetailPage));
I hope this helps.

Spring custom Generic converter not working

In my spring mvc web-application i use a generic converter that converts String (id) to Company by fetch using (service and dao) components
first of all in my MVC-config i add the converter like follow :
#Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new GenericIdToCompanyConverter(new CompanyServiceImp()));
}
companyService
#Service
#Transactional
#Qualifier("companyService")
public class CompanyServiceImp implements ICompanyService {
#Resource
#Qualifier("companyDAO")
private ICompanyDao dao;
public void setDao(ICompanyDao dao) {
this.dao = dao;
}
#Override
public Company find(Long id) throws BusinessException {
Company current = dao.find(id);
if(current == null) {
throw new BusinessException("notFound");
}
return current;
}
....
}
Generic converter :
public class GenericIdToCompanyConverter implements GenericConverter {
private ICompanyService companyService;
public GenericIdToCompanyConverter(ICompanyService companyService) {
super();
this.companyService = companyService;
}
#Override
public Set<ConvertiblePair> getConvertibleTypes() {
ConvertiblePair[] pairs = new ConvertiblePair[] { new ConvertiblePair(Number.class, Company.class), new ConvertiblePair(String.class, Company.class) };
return ImmutableSet.copyOf(pairs);
}
#Override
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
long id = 0;
if( sourceType.getType() == String.class) {
try {
id = Long.valueOf((String) source);
}catch(NumberFormatException e) {
return null;
}
}else if( sourceType.getType() == Number.class) {
id = (Long) source;
}else {
return null;
}
try {
return companyService.find(Long.valueOf(id));
} catch (BusinessException e) {
return null;
}
}
}
and here the controller that receives data form (via ajax request)
public #ResponseBody JsonResponseBean applay(#Valid VoucherForm form, BindingResult result, Locale locale) throws BusinessException {
....
}
where VoucherForm has these attributes
public class VoucherForm{
protected Long id;
protected Company company;
...
}
when i run the application and call controller method it returns type mismatch error for company attribute
and when i execute this on debug mode i see that it fails on serviceCompany - dao.find(id) statment where my dao is == null
Please help
finally i have to autowire the converter
Mvc-config
....
#Autowired
private GenericIdToCompanyConverter genericIdToCompanyConverter;
#Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(genericIdToCompanyConverter);
}
and update the converter like follow :
public class GenericIdToCompanyConverter implements GenericConverter {
#Resource
#Qualifier("companyService")
private ICompanyService companyService;
#Override
public Set<ConvertiblePair> getConvertibleTypes() {
....
}
#Override
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
....
}
}

Unit Test issues with Entity FrameWork (nullable values)

im trying to implement a uniTest for my application so when i tried to get User by ID value in my application it's work fine, but when i tried to do the same scenario from my unit test class i always get nullable result even if the ID value is correct :
Class AccountController : ApiController
{
private UserService _UserService = null;
public AccountController()
{
_UserService = new UserService();
}
[AllowAnonymous]
[Route("test")]
public IHttpActionResult test()
{
var user = _UserService.getUserById(1); //user --> not null;
}
}
but when i tried a UnitTest Script
[TestClass]
public class userServiceTest
{
private UserService _UserService = null;
public userServiceTest()
{
_UserService = new UserService();
}
[TestMethod]
public void checkUserCase1()
{
var user = _UserService.getUserById(1); //user is null value !!!;
}
}
User Service :
public class UserService
{
private GenericRepository<User> _UserRepository = null;
public UserService()
{
_UserRepository = new GenericRepository<User>();
}
public User getUserById(int id)
{
return _UserRepository.Find(x => x.Id == id).FirstOrDefault();
}
}
The Generic Repository
public class GenericRepository<T> : IGenericRepository<T> where T : class
{
private MyDbContext db = null;
private DbSet<T> table = null;
public IEnumerable<T> Find(Expression<Func<T, bool>> predicate)
{
return table.Where(predicate);
}
}
IGeneric :
public interface IGenericRepository<T> where T : class
{
IEnumerable<T> SelectAll();
T SelectByID(object id);
void Insert(T obj);
void Update(T obj);
void Delete(object id);
void Save();
IEnumerable<T> Find(Expression<Func<T, bool>> predicate);
}
My DB Context :
public class MyDbContext : DbContext
{
public MyDbContext()
: base("AuthWebApiDb")
{
Database.SetInitializer<MyDbContext>(new MyDbInitializer());
}
public DbSet<User> Users { get; set; }
}
I have Two Project : One is the simple project, the second is the Unit Test
Check if EF is innstalled in your UnitTest project.
Put the connection string in the app.config file in the unitest project.
Thank's #Stewart_T

JSF custom panel with button - action not invoked

I have built a custom component button, but somehow the action is not invoked. When debugging the getAction-Method within the component and invoking the supplied MethodeExpression the Bean-Method is called as expected. But due to some reason, the Expression is not invoked when pressing the button in the browser.
Is there some kind of additional Interface necessary to pass the action to the embedded button-component?
Any help is very appreciated since I am stuck at this issue for some days now
MyClass:
public class MyClass extends UIPanel implements SystemEventListener
{
private UIForm form;
private HtmlCommandButton buttonOk;
public MyClass()
{
FacesContext context = getFacesContext();
UIViewRoot root = context.getViewRoot();
root.subscribeToViewEvent(PostAddToViewEvent.class, this);
}
#Override
public void processEvent(SystemEvent event)
{
this.form = new UIForm();
this.buttonOk = new HtmlCommandButton();
this.buttonOk.setId("okButtonId");
this.buttonOk.setActionExpression(getAction());
this.buttonOk.setValue("OK");
this.form.getChildren().add(this.buttonOk);
getChildren().add(this.form);
}
private enum PropertyKeys
{
action, text, titel
}
public MethodExpression getAction()
{
return (MethodExpression) getStateHelper().eval(PropertyKeys.action);
}
public void setAction(MethodExpression actionExpression)
{
getStateHelper().put(PropertyKeys.action, actionExpression);
}
public String getText()
{
return (String) getStateHelper().eval(PropertyKeys.text);
}
public void setText(String text)
{
getStateHelper().put(PropertyKeys.text, text);
}
public String getTitel()
{
return (String) getStateHelper().eval(PropertyKeys.titel);
}
public void setTitel(String titel)
{
getStateHelper().put(PropertyKeys.titel, titel);
}
#Override
public void encodeAll(FacesContext context) throws IOException
{
ResponseWriter writer = context.getResponseWriter();
writer.startElement(HTML.DIV_ELEM, this);
writer.writeText(getText(), null);
this.form.encodeAll(context);
writer.endElement(HTML.DIV_ELEM);
}
#Override
public void encodeChildren(FacesContext context) throws IOException
{
}
#Override
public boolean isListenerForSource(Object source)
{
return (source instanceof MyClass);
}
}
MyClassHandler:
public class MyClassHandler extends ComponentHandler
{
public MyClassHandler(ComponentConfig config)
{
super(config);
}
#SuppressWarnings("rawtypes")
#Override
protected MetaRuleset createMetaRuleset(Class type)
{
return super.createMetaRuleset(type).addRule(new MethodRule("action", String.class, new Class[] { ActionEvent.class }));
}
}
myView Method:
...
public String myMethod()
{
System.err.println("myMethod");
return "/some/path/yadayada.xhtml";
}
...
MyView.xhtml
<myTag action="#{myView.myMethod}" id="id1" titel="bla" text="bleh" />
Exdending UICommand is enough, since you only want one action to be executed.
You have to provide two additional MethodExpressions via the tag-attributes and within the decode-method you can check which button has been pressed and redirect the particular MethodExpression to the standard-action provided by UICommand. This way, you dont have to worry about the legacy-interface ActionSource, or how Events are broadcasted.
public void decode(FacesContext contex)
{
Map<String,String> map = context.getExternalContext.getRequestParameterMap();
// your rendered buttons need a name you check for
final boolean okPressed = map.containsKey( getClientId + ":ok" );
final boolean cancelPressed = map.containsKey( getClientId + ":cancel" );
if(okPressed || cancelPressed)
{
MethodExpression exp = null;
if(okPressed)
{
exp = getActionOk();
}
else
{
exp = getActionCancel();
}
// redirect to standard action
setActionExpression(exp);
queueEvent(new ActionEvent(this));
}
}
In order to make use of of this you need two attributes (actionOk and actionCancel) which use Method Expressions (setter and getter). Those have to be configured by a ComponentHandler as you did for the action-attribute.

Resources