Realtime validation of a button, using fody - xamarin.forms

I a trying to disable and enable a button based on user input. I implemented fody property changed Nuget package, to help me reduce my code a bit.
and it works, when I start typing, the breakpoint in my LoginViewModel gets hit and display my values ViewModel getting hit every time I type
but I can't seem to trigger CanLogin() method
[AddINotifyPropertyChangedInterface]
public class LoginPageViewModel {
public ICommand OpenRegisterPopupCommand { get; set; }
public ICommand Register { get; set; }
public ICommand Login { get; set; }
public Users Users { get; set; }
public bool IsPopUpOpen { get; set; }
public LoginPageViewModel() {
Users = new Users();
Login = new Command(LoginAction, CanLogin);
Register = new Command(RegisterAction);
OpenRegisterPopupCommand = new Command(() => {
IsPopUpOpen = true;
});
}
private void LoginAction(object obj) {
throw new NotImplementedException();
}
private bool CanLogin(object arg) {
if (Users != null && !string.IsNullOrEmpty(Users.Email) && !string.IsNullOrEmpty(Users.Password)) {
return true;
}
return false;
}

You are using a Command with a CanExecute method. If the CanExecute method returns false, the command will not ve able to be executed. But this validation does not happen all the time, you have to trigger it.
You have to call Login.ChangeCanExecute() when you modify any of the related properties (like Users, Users.Email or Users.Password), this will fire the CanExecute validation of the command.
Command documentation.

Related

What would be the best/simplest solution to retrieve values from my database for comparison? - ASP.NET Core

I'm currently stuck on accessing all of the 'UserName' values from my database.
I am doing this so I can compare the user input for a username to check if it has been used before (I don't want two instances of the same username). This is on a .cshtml.cs page.
I am already able to access the database through my program, as create commands have been tested and do work.
My program is on ASP.NET 6.0 Core Web App.
I am a student with basic knowledge on ASP.NET Core, and on how to solve this issue, therefore as much simplified explanation would be very appreciated.
Here is my code:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using AQA_A_Level_CS_NEA__Suvat_Solver_.Models;
using AQA_A_Level_CS_NEA__Suvat_Solver_.Data;
namespace AQA_A_Level_CS_NEA__Suvat_Solver_.Pages.UserLogin
{
[BindProperties(SupportsGet = true)]
public class RegisterPageModel : PageModel
{
public new TempUserLoginModel TempUser { get; set; }
public bool HasPassword { get; set; } = true;
public bool HasUsername { get; set; } = true;
public bool UniUsername { get; set; } = true;
public bool RegisterApproved { get; set; } = false;
public bool AQAPhys { get; set; } = false;
public bool AQAMaths { get; set; } = false;
public bool SubjectChosen { get; set; } = true;
private readonly ApplicationDbContext _context;
public RegisterPageModel(ApplicationDbContext context)
{
_context = context;
}
public List<User> UserList = new List<User>();
public void OnGet()
{
}
public IActionResult OnPost()
{
User User = new User();
HasPassword = true;
HasUsername = true;
UniUsername = true;
SubjectChosen = true;
UserList = _context.User.ToList();
if (!AQAMaths && !AQAPhys)
{
SubjectChosen = false;
}
if (string.IsNullOrWhiteSpace(TempUser.Password) || TempUser.Password.Length < 4)
{
HasPassword = false;
}
if (string.IsNullOrWhiteSpace(TempUser.Username) || TempUser.Username.Length < 4)
{
HasUsername = false;
}
if (TempUser.Username == //database UserName value here )
{
//Here would be where the Username is compared
//UniUsername = false;
}
if (!HasPassword || !HasUsername || !UniUsername || !SubjectChosen)
{
return RedirectToPage("/UserLogin/RegisterPage", new { HasPassword, HasUsername, UniUsername, SubjectChosen });
}
else
{
RegisterApproved = true;
User.UserName = TempUser.Username;
User.UserPass = TempUser.Password;
User.UserCorrectAnsw = 0;
User.UserTotalAnsw = 0;
_context.User.Add(User);
_context.SaveChanges();
return RedirectToPage("/UserLogin/LoginPage", new { RegisterApproved });
}
}
}
}
Many Thanks.
Probably the strongest method is to enforce the user name column to be unique at the database level using a Unique Constraint. That way if you try to add a user with a duplicate user name, the database will simply return an error.
This article shows how to create a Unique Constraint with Entity Framework
You can be sure that the database will not allow a user with a duplicate user name with this method. However, trying to add a duplicate user will create an error which you will have to either handle or prevent from occurring in the first place (which is what you are doing now)
So for the code you are using now, since you already have the users pulled from the database here:
UserList = _context.User.ToList();
We can use LINQ to check if any of the users Usernames in UserList matches the TempUser like this:
if (UserList.Any(x => x.Username == TempUser.Username))
{
//Here would be where the Username is compared
UniUsername = false;
}
Since you didn't share your User model, this assumes your User class has a property named Username.
Happy Coding

Asp.Net IdentityUser add custom List Property

I am fairly new to coding with asp.net so there might be an obvious answere to my question but I haven't found one yet.
So currently I am developing a site for project management and I want the users to get notified when an event happens, eg. they were added to a new project, a project has been updated etc.
For that I have expanded the IdentityUser Model with a new property List
public class CojectUser : IdentityUser
{
public List<Notification> Notifications { get; set; }
}
public class Notification
{
public int NotificationID { get; set; }
public string Message { get; set; }
public bool Seen { get; set; }
}
When an event happens I add them to the user's notification list and update the user via the userManager.
public class EventBroker<T> : IEventBroker<T>
{
private readonly UserManager<CojectUser> userManager;
public EventBroker(UserManager<CojectUser> userMgr, IUserValidator<CojectUser> userValid)
{
userManager = userMgr;
}
public async Task NotifyAsync(Message<T> message, List<UserRole> recipients)
{
foreach (var user in recipients)
{
var cojectUser = await userManager.FindByNameAsync(user.Name);
if (cojectUser != null)
{
if (cojectUser.Notifications == null)
{
cojectUser.Notifications = new List<Notification>();
}
cojectUser.Notifications.Add(new Notification
{
Message = message.Information,
Seen = false
});
IdentityResult result = await userManager.UpdateAsync(cojectUser);
if (!result.Succeeded)
{
throw new UserUpdateFailException();
}
}
}
}
}
}
I am able to save the custom data to the database, but I am unable to load it again from database.
When I want to display the user's notifications userManager retrieves an user object with null as notification list. Even though the data is stored in database.
public async Task<IActionResult> Index()
{
CojectUser user = await userManager.GetUserAsync(User);
if(user.Notifications == null)
{
user.Notifications = new List<Notification>();
}
return View(user);
}
Data in database:
Can anybody tell me what I am doing wrong?
UserManager don't eager load properties by default.
You should use DatabaseContext directly.
var user = _context.Users.Include(c => c.Notifications).Where(u => u.Id == user.Id).ToList();

Xamarin.Forms ListView with ReactiveUI does not update new items

I am developing a Xamarin.Forms app. It have SearchBar in the NavigationBar, ListView in the ContentPage and a Entry with AddButton in the bottom. When user click on the AddButton the text in the Entry adds to the realm mobile database. Which autorefresh the IEnumerable. The ListView that is bind to IEnumerable auto updates.
public class MainViewModel : ReactiveObject
{
public IEnumerable<Company> Companies { get; set; }
[Reactive]
public string Query { get; set; }
public string NewCompany { get; set; }
public ReactiveCommand<Unit, Unit> AddCompanyCommand { get; set; }
public ReactiveCommand<Unit, IEnumerable<Company>> SearchCommand { get; set; }
Realm _realm;
public MainViewModel()
{
_realm = Realm.GetInstance();
Companies = _realm.All<Company>();
AddCompanyCommand = ReactiveCommand.CreateFromTask(async () => await AddButtonClicked());
SearchCommand = ReactiveCommand.Create<Unit, IEnumerable<Company>>(
_ =>
SortCollection()
);
SearchCommand.ToProperty(this, nameof(Companies));
this.WhenAnyValue(x => x.Query).Throttle(TimeSpan.FromSeconds(1)).Select(_ => Unit.Default).InvokeCommand(this, x => x.SearchCommand);
}
async Task AddButtonClicked()
{
if (!string.IsNullOrWhiteSpace(NewCompany))
{
_realm.Write(() =>
{
_realm.Add(new Company { Name = NewCompany });
});
NewCompany = string.Empty;
}
}
IEnumerable<Company> SortCollection()
{
if (string.IsNullOrWhiteSpace(Query))
{
Companies = Companies.Where(x => x.Name != string.Empty);
}
else
{
Companies = Companies.Where(x => x.Name.IndexOf(Query, StringComparison.InvariantCultureIgnoreCase) >= 0);
}
return Companies;
}
}
Recently when I added Search Logic to the ViewModel the ListView is not Auto Updating. I either have to search or restart the app to display the new item in the ListView. When I comment out the following line the ListView starts auto updating.
SearchCommand.ToProperty(this, nameof(Companies));
But then it stops displaying Search Results. I want both Auto updating with new item and displaying search result functionalities in the ListView.
At first glance, your public IEnumerable<Company> Companies { get; set; } isn't notifying property change events.
The fact that you need to tell the runtime that the property has changed so you need to implement notify property changed interface
Look at this another stackoverflow thread.
Implementing INotifyPropertyChanged - does a better way exist?
Also there is is a plugin named fody which automatically injects propertychanged code into every setter of the properties in the project. Without needing you to do anything.
Install both of them in the project where you are writing your properties, it will automatically inject property changed code while compiling.
https://www.nuget.org/packages/Fody/
https://www.nuget.org/packages/PropertyChanged.Fody/

Display Information to the UI

So what I have been trying is this: After successful registration the user gets a Message in the interface to show that Registration was successful. My first method was I declared a Message variable and use Data Binding to bind the result to a label in my RegisterPage.xaml. That failed because whether the message is successful or not the label is not showing. So I commented out using a label and tried DisplayAlert but DisplayAlert is giving an error- does not exist in the current context.
Please help, still learning.
public class RegisterViewModel
{
private readonly DataService dataService = new DataService();
public string Email { get; set; }
public string Password { get; set; }
public string ConfirmPassword { get; set; }
public string Message { get; set; }
public ICommand RegisterCommand
{
get
{
return new Command(async () =>
{
var isRegistered = await dataService.RegisterUserAsync(Email, Password, ConfirmPassword);
Settings.Username = Email;
Settings.Password = Password;
if (isRegistered)
{
//DisplayAlert( "Alert" , "Registered", "OK");
//Message = "Registered Successfully :)";
// DependencyService.Get<Toast>().Show("You have registered succefully");
Application.Current.MainPage = new NavigationPage(new EntryPage());
}
else
{
Message = " Retry Later :(";
}
});
}
}
}
DisplayAlert is part of the Page class. If you want to display an alert from a view model (there are many results on Google), you'd call a method like:
private async Task DisplayGenericDialog(string title, string message)
{
await App.Current.MainPage.DisplayAlert(title, message, "OK");
}

How to persist an object for longer than a request

I'm trying to implement a very simple api. It should instantiate a tv object which status should be changed (from off to on and from on to off). My current problem is that after I change the status in a get-method the tv object is reinstantiated.
Is there a simple way to persist the object for longer than one request?
Here my code:
public class TvController : ApiController
{
Tv tv = new Tv(null, null, false);
// GET: api/Tv
[HttpGet]
public bool Get()
{
if (!tv.Status) { tv.Status = true; }
else { tv.Status = false; }
return tv.Status;
}
public class Tv
{
public string Channel { get; set; }
public string Volume { get; set; }
public bool Status { get; set; }
public Tv(string channel, string volume, bool status)
{
Channel = channel;
Volume = volume;
Status = status;
}
}
}
Since your API is stateless, you would need to figure out a way to persist the request with some sort of lookup table (perhaps you store the API key along with the object associated with it in a Redis node)
I'm not sure you can use Session with an API Controller as that likely defeats the whole point, but if you could, you would do the following.
And your code would need to be updated to do this:
if( Session["TVObject"] == null) {
Tv tv = new Tv(null, null, false);
Session.Add("TVObject", tv);
} else {
Tv tv = Session["TVObject"] as Tv;
}

Resources