I have a Maui app with a view model. The ViewModel has the following property:
[ObservableProperty]
public UserAccountDTO userAccount = new UserAccountDTO();
UserAccountDTO has the following property:
public partial class UserAccountDTO: ObservableValidator
{
[Required(AllowEmptyStrings = false, ErrorMessage = "Firstname required")]
[MaxLength(10, ErrorMessage = "Text length is maximum 10!")]
[ObservableProperty]
public string firstName;
}
I have the firstName bound to an Entry.
In the VM, when I call ValidateAllProperties() I don't get any errors coming back from this class. I.e. if FirstName is blank HasErrors is still false.
[RelayCommand]
private async void CreateAccountPressed()
{
ValidateAllProperties();
string Error = string.Empty;
if (HasErrors)
Error = string.Join(Environment.NewLine, GetErrors().Select(e => e.ErrorMessage));
}
Am I missing something?
Thanks
If you want to set the ObservableValidator for the firstName, you should add the get and set method to the Firstname.
[Required(AllowEmptyStrings = false, ErrorMessage = "Firstname required")]
[MaxLength(10, ErrorMessage = "Text length is maximum 10!")]
[ObservableProperty]
public string FirstName
{
get => this.firstName;
set => SetProperty(ref this.firstName, value, true);
}
Related
This question already has answers here:
Property value doesn't update value to Label in UI in Xamarin Forms
(2 answers)
Closed 1 year ago.
The following Label does not show data while running it <Label Text="{Binding Firstname}"/> if I run code in Debug mode and if I change Label to Editor or something else it shows data.
Please let me know why is that and how can I solve it.
Code Behind
Private fields
private string email;
private string phone;
private string firstname;
private string lastname;
Method calling data from FirebaseFirestore
public async Task GetDataAsync()
{
var user = await DependencyService.Get<IAccountService>().GetUserAsync();
phone = user.Phone;
email = user.Email;
firstname = user.Firstname;
lastname = user.Lastname;
}
Public properties
public string Firstname
{
get { return firstname; }
set
{
firstname = value;
OnPropertyChanged(nameof(Firstname));
}
}
public string Lastname
{
get {return lastname;}
set
{
lastname = value;
OnPropertyChanged(nameof(Lastname));
}
}
public string Email
{
set
{
if (email != value)
{
email = value;
OnPropertyChanged("Email");
}
}
get
{
return email;
}
}
public string Phone
{
set
{
if (phone != value)
{
phone = value;
OnPropertyChanged("Phone");
}
}
get
{
return phone;
}
}
This line:
firstname = user.Firstname;
Must be changed to:
Firstname = user.Firstname;
Explanation:
If you don't use the Firstname property setter, then OnPropertyChanged(nameof(Firstname)); never gets called.
So XAML does not know that the property's value has changed.
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");
}
I am trying to use identity with DB first and I followed the this link https://www.youtube.com/watch?v=elfqejow5hM. I am getting an error "Name cannot be null or empty." I don't have any column Name. And also does not called the "OnModelCreating".
this is my application user class
public class MyUser : IdentityUser<long, MyLogin, MyUserRole, MyClaim>
{
public string UserName { get; set; }
}
public class MyUserRole : IdentityUserRole<long> { }
public class MyRole : IdentityRole<long, MyUserRole> { }
public class MyClaim : IdentityUserClaim<long> { }
public class MyLogin : IdentityUserLogin<long> { }
this is my onmodelcreating code
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<MyUser>().ToTable("AspNetUser");
modelBuilder.Entity<MyUserRole>().ToTable("AspNetRole");
modelBuilder.Entity<MyRole>().ToTable("AspNetRole");
modelBuilder.Entity<MyClaim>().ToTable("AspNetUserClaim");
modelBuilder.Entity<MyLogin>().ToTable("AspNetUserLogin");
modelBuilder.Entity<MyUser>().Property(r => r.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<MyRole>().Property(r => r.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<MyClaim>().Property(r => r.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
and my register post method is
var manager = HttpContext.GetOwinContext().GetUserManager<MyUser>();
var user = new MyUser()
{
Email = model.Email,
EmailConfirmed = false,
PhoneNumberConfirmed = false,
TwoFactorEnabled = false,
LockoutEndDateUtc = DateTime.Now,
LockoutEnabled = false,
AccessFailedCount = 0,
UserName = model.userName
};
IdentityResult result = await UserManager.CreateAsync(user, model.Password);
Can any one help me the cause for the error.
i've a view. in the view i've months field(nvarchar type in database) :
#Html.DropDownListFor(model => model.rent_month,
(IEnumerable<SelectListItem>)ViewBag.months)
i've a method in a model class (PostManager) to generate months list like:
public IEnumerable<SelectListItem> GetMyMonthList()
{
return CultureInfo.CurrentCulture.DateTimeFormat.MonthNames
.Select(m => new SelectListItem() { Text = m, Value = m });
}
i get months in get action by :
public ActionResult Create()
{
PostModel p = new PostModel();
ViewBag.months = pm.GetMyMonthList();
return View(p);
}
in my Model my month attributes:
[Required(ErrorMessage = "You Must Select a Month.")]
[Display(Name = "Select Rent Month")]
public string rent_month { get; set; }
in the post action:
public ActionResult Create(PostModel p)
{
if (ModelState.IsValid)
{
post post = new Models.DB.post();
post.rent_month = p.rent_month;
db.posts.AddObject(post);
db.SaveChanges();
}
}
it generates month in the dropdownlist correctly.But after submit the form it gives error:
The ViewData item that has the key 'rent_month' is of type 'System.String' but must be of type 'IEnumerable'
now what is the solution for this error... thanks in advance...
I believe this is happening because in your post action you are not populating the ViewBag again. Make sure you set ViewBag.months = pm.GetMyMonthList(); in your controller POST action similar to what you have done in GET action.
Better solution would be to have a IEnumerable<SelectListItem> MonthList property as part of the PostModel. Instead of loading the months from ViewBag you can access it directly by the MonthList property
In the PostModel
public IEnumerable<SelectListItem> MonthList
{
get
{
return pm
.GetMonthList()
.Select(a => new SelectListItem
{
Value = a.Id,
Text = a.MonthText
})
.ToList();
}
}
Then in the view
#Html.DropDownListFor(model => model.rent_month, Model.MonthList)
After EDIT to the question
Your PostModel class should be like this. I have moved your GetMyMonthList() implementation out of the PostManager class.
public class PostModel
{
[Required(ErrorMessage = "You Must Select a Month.")]
[Display(Name = "Select Rent Month")]
public string rent_month { get; set; }
public IEnumerable<SelectListItem> MonthList
{
get
{
return CultureInfo.CurrentCulture.DateTimeFormat.MonthNames
.Select(m => new SelectListItem() { Text = m, Value = m });
}
}
}
public class PostModel
{
[Required(ErrorMessage = "You Must Select a Month.")]
[Display(Name = "Select Rent Month")]
public string rent_month { get; set; }
public IEnumerable<SelectListItem> MonthList
{
get
{
return CultureInfo.CurrentCulture.DateTimeFormat.MonthNames
.Select(m => new SelectListItem() { Text = m, Value = m });
}
}
}
I am having problem getting values of a class whose one property is another class.
Here is an example:
public class Person
{
private int age;
private string name;
public Person()
{
Address = new Address();
}
public int Age
{
get { return age; }
set { age = value; }
}
public string Name
{
get { return name; }
set { name = value; }
}
public Address Address { get; set; }
}
public class Address
{
public string street { get; set; }
public string houseno { get; set; }
}
public class Program
{
static void Main(string[] args)
{
Person person = new Person();
person.Age = 27;
person.Name = "Fernando Vezzali";
person.Address.houseno = "123";
person.Address.street = "albert street";
Type type = typeof(Person);
PropertyInfo[] properties = type.GetProperties();
foreach (PropertyInfo property in properties)
{
Console.WriteLine("{0} = {1}", property.Name, property.GetValue(person, null));
}
}
}
But with this I dont get values of address.
Can someone help here?
Here is the possible ToString, taking into account the Jason's answer...
You can also cast your returned reflected objet into an Address to access the full object and properties
public class Address
{
public string street { get; set; }
public string houseno { get; set; }
public override ToString() {
return string.Format("street: {0}, house: {1}", street, houseno);
}
}
type.GetProperties() only gets the properties for that type, one of which is an object Address. street and houseno are not properties on Person.
Console.Write... implicitly calls ToString() on each parameter. So you probably see "Address - Namespace.Address" as an output, because someAddressObject.ToString() will return the type name.
The easiest way to get what you want for this specific situation is to override ToString() on your Address object to output some meaningful string representation of the object:
public override ToString()
{
return string.Format("#{0} {1}",
this.houseno,
this.street); //returns #123 StreetName
}
If you actually need to write every property of every sub-object on your object, that can get fairly complex - you're essentially talking about serialization, which recurses down an object tree and into each object.
Either you need to implement ToString() in Address, if you're happy with returning a formatted string as the value of Address, or your iteration code needs to inspect each property to determine whether that property's type also exposes properties, and enqueue it for further inspection.
Your foreach is iterating through all properties properly, and I beleive it is implicitely calling ToString on it to get the value, so override the ToString method of your Address class, and return the properties as a string.
Or, in the foreach, test to see if your property is a value type or a class type by getting the property type and checking IsValueType or IsClass. If IsValueType is false, then iterate through the properties of that properties' class type just as you did for the properties of Person.
Something like this (You may need to tweek to get this to compile, but it gives you the idea):
Person person = new Person();
person.Age = 27;
person.Name = "Fernando Vezzali";
person.Address.houseno = "123";
person.Address.street = "albert street";
Type type = person.GetType();
PropertyInfo[] properties = type.GetProperties();
foreach (PropertyInfo property in properties)
{
//get the type of this property
Type tyProperty = property.PropertyType;
object oValue = property.GetValue(person, null));
//if the property is a value
if (tyProperty.IsValueType)
{
Console.WriteLine("{0} = {1}", property.Name, oValue);
}
else //else if property type is a class
{
oSubValue = property.GetValue(oValue, null));
//loop through the classes properties
PropertyInfo[] lstSubProperties = tyProperty.GetProperties();
foreach (PropertyInfo propSub in lstSubProperties)
{
Console.WriteLine("{0} = {1}", propSub .Name, oSubValue);
}
}
}