How to Deactive Injected ViewModel into ContentControl - caliburn.micro

How to Deactive Injected ViewModel into ContentControl
[Import]
public IMyViewModel MyViewModel { get; set; }
public void ClickButton
{
//This Method Not Deactive MyViewModel
MyViewModel.Deactivate(true);
}
<ContentControl x:Name="MyViewModel" />

Related

My dbContext return null, when I want get list of user, which are from identity

My dbContext return null, when I want get list of user in Index View. This list are from my database AspNetUsers table, which has been generate by identity. I can get other my database table list.
There is my ApplicationDbContext
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<ProductCategory> ProductCategories { get; set; }
public DbSet<ProductBrand> ProductBrands { get; set; }
public DbSet<Product> Products { get; set; }
public DbSet<ApplicationUser> ApplicationUsers { get; set; }
public DbSet<Address> Address { get; set; }
public DbSet<Recipe> Recipes { get; set; }
public DbSet<Order> Orders { get; set; }
public DbSet<Order_detail> Order_Details { get; set; }
}
There is my UserController
[Area("Admin")]
public class UserController : Controller
{
UserManager<IdentityUser> _userManager;
private ApplicationDbContext _db;
public UserController(UserManager<IdentityUser> userManager, ApplicationDbContext db)
{
_userManager = userManager;
_db = db;
}
public IActionResult Index()
{
return View(_db.ApplicationUsers.ToList());
}
}
There is my ApplicationUser.Model, which inherit IdendityUser
public class ApplicationUser : IdentityUser
{
public string Name { get; set; }
public string Surname { get; set; }
public ICollection<Recipe> Products { get; set; }
public ICollection<Order> Orders { get; set; }
}
I don't know how you register ApplicationDbContext and Identity framework on your ASP.NET Core MVC application because you didn't show them on the question.
There are couple problems in your code.
First, if you have a custom IdentityUser, like the ApplicationUser you have, you would have to use the generic version of IdentityDbContext:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
...
}
You would need to use the matching generic version of IdentityDbContext if you have any of following:
Custom IdentityUser
Custom IdentityRole
Custom primary key
All 7 classes, user and role, plus IdentityUserRole, IdentityUserClaim, IdentityRoleClaim, IdentityUserLogin, and IdentityUserToken
After you register your custom class with IdentityDbContext, you don't need to put the class as one of the DbSet<> there:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
...
public DbSet<ProductCategory> ProductCategories { get; set; }
public DbSet<ProductBrand> ProductBrands { get; set; }
public DbSet<Product> Products { get; set; }
// public DbSet<ApplicationUser> ApplicationUsers { get; set; }
public DbSet<Address> Address { get; set; }
public DbSet<Recipe> Recipes { get; set; }
public DbSet<Order> Orders { get; set; }
public DbSet<Order_detail> Order_Details { get; set; }
}
You would also need to use the generic version of AddIdentity<TUser>, AddDefaultIdentity<TUser>, or AddIdentityCore<TUser> in your Startup.cs, depending on what you need:
AddDefaultIdentity = AddIdentity + AddDefaultTokens + AddDefaultUI
You didn't specify what version of ASP.NET Core Identity you're using so I don't exactly know which one you use, but the following is how I registered it:
services.AddIdentity<ApplicationUser, ApplicationRole>(options =>
{
options.User.RequireUniqueEmail = ...;
...
})
.AddEntityFrameworkStores<ApplicationDbContext>();
I have all 7 classes customized as well as change the primary key from string to Guid.
Lastly, to use the dependency injected UserManager and SignInManager, you would need to correct generic version of them as well:
[Area("Admin")]
public class UserController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
public UserController(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
public IActionResult Index()
{
// Get the user list
var users = _userManager.Users.ToList();
// Build your view model to define what your UI only needs, not just passing
// everything to it
var vm = new UserManagementListViewModel
{
Users = users.Select(x => new UserViewModel
{
UserId = x.Id,
UserSurname = x.Surname,
ProductCount = x.Products.Count(),
OrderCount = x.Orders.Count()
})
};
return View(vm);
}
}

main page doesn't get updated after initialisation is finished

I am having issues with binding context, after initialisation it doesn't update. so the button is not clickable and the name label doesn't update as its stated in ctor. This is the first and only page.
Page
<Label x:Name="NamesLabels" Text="{Binding Name}"/>
<Button HorizontalOptions="FillAndExpand" Text="Show scanner" Command="{Binding ShowScannerCommand}"/>
public MainPage()
{
InitializeComponent();
}
protected override void OnAppearing()
{
base.OnAppearing();
BindingContext = new MainPageViewModel();
}
//also tried
protected override void OnAppearing()
{
base.OnAppearing();
var context = new MainPageViewModel();
BindingContext = context;
name.Source = context.Name;
btn.Command = context.ShowScannerCommand;
}
ViewModel
public string Name
{
get => _name;
private set
{
_name = value;
NotifyPropertyChanged("Name");
}
}
public ICommand ShowScannerCommand { get; private set; }
public MainPageViewModel()
{
Name = "rwatag";
//have tried _name = "rwatag";
ShowScannerCommand = new Command(() => ShowScanner());
}
void ShowScanner()
{
System.Diagnostics.Debug.WriteLine("result");
}
this is what I get after clicking on button and when debugging the code doesn't get fired
[InputEventReceiver] Slow Input: took 118ms in dispatching, now at finishInputEvent (MotionEvent: event_seq=0, seq=78288, action=ACTION_DOWN)
Resolved pending breakpoint at '/Users/de/Projects/Demo/Demo/View/MainPage.xaml.cs:26,1' to void Demo.MainPage.OnAppearing () [0x00014].
[zygote] Do partial code cache collection, code=61KB, data=59KB
[zygote] After code cache collection, code=61KB, data=59KB
[zygote] Increasing code cache capacity to 256KB
I use your code and it works well on my side. I just add a string _name { get; set; } property and implement the INotifyPropertyChanged interface in MainPageViewModel.
Here is the code example:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
BindingContext = new MainPageViewModel();
}
}
public class MainPageViewModel : INotifyPropertyChanged
{
string _name { get; set; }
public string Name
{
get => _name;
private set
{
_name = value;
OnPropertyChanged("Name");
}
}
public ICommand ShowScannerCommand { get; private set; }
public MainPageViewModel()
{
Name = "rwatag";
ShowScannerCommand = new Command(() => ShowScanner());
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
void ShowScanner()
{
System.Diagnostics.Debug.WriteLine("result");
}
}

View Modeling: List field

I have a Form class that has a List<FormField>.
public class Form
{
public int ID { get; set; }
public int templateID { get; set; }
public List<FormField> fields { get; set; }
public Form()
{
fields = new List<FormField>();
}
}
The FormField:
public class FormField
{
public object value { get; set; }
public TemplateField templateField {get;set;}
}
And the TemplateField:
public class TemplateField
{
public int ID { get; set; }
public string fieldDescription { get; set; }
public TemplateFieldType type { get; set; }
}
My controller class:
public class MedicalAppointment : Controller
{
public IActionResult Index()
{
Template template = new TemplateDataMapper().GetMedicalAppointmentTemplate();
Form form = new Form();
form.templateID = template.ID;
foreach(TemplateField field in template.fields)
{
FormField formField = new FormField();
formField.templateField = field;
form.fields.Add(formField);
}
return View(form);
}
public IActionResult TemplateManagement()
{
return View();
}
[HttpPost]
public void SaveForm(Form form)
{
......
}
My view looks like this:
#model Form
....
#using (Html.BeginForm("SaveForm", "MedicalAppointment", FormMethod.Post, new { id = "registerDonorForm" }))
{
<table class="personal-data">
#for(int i=0; i<Model.fields.Count; i++)
{
<tr>
<th>#Html.LabelFor(model => Model.fields[i].templateField.ID, Model.fields[i].templateField.fieldDescription)</th>
<th>#Html.TextBoxFor(model => Model.fields[i].value)</th>
</tr>
}
</table>
<div class="register-button">
<input type="submit" value="Registar" />
</div>
}
</div>
I want to create a dynamic form, where when I submit it, I could receive a Form with the field[i].value.
My problem is that, when I submit the form, in the controller, I don't receive any value submitted by the user. The Form is received with the FormField.Value null as well the Form.FormField.TemplateField.ID.
Any one can help me with that?
Note: Forget the class names on html and other wrong names.
Thank you in advance

Add MVC 5 UserManager<ApplicationUser> to register with Unity Framework?

Hi i am using MVC 5 + EF6 and want to register MVC 5 Application User and other specific types using Unity 3 but i am getting errors.
My Context Class:
public class ProjectContext : IdentityDbContext<ApplicationUser>
{
public ProjectContext()
: base("ProjectContext")
{
}
public DbSet<User> Users { get; set; }
public DbSet<UserProfile> UserProfile { get; set; }
public virtual void Commit()
{
base.SaveChanges();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
Controller Class:
public class AccountController : Controller
{
private UserManager<ApplicationUser> UserManager;
private IUserService userService;
private IUserProfileService userProfileService;
public AccountController(IUserService userService, IUserProfileService userProfileService, UserManager<ApplicationUser> userManager)
{
this.userService = userService;
this.userProfileService = userProfileService;
this.UserManager = userManager;
}
}
I have used the following registration in combinations but i am getting errors
--> ProjectArchitecture.Web.Controllers.AccountController does not have a constructor that takes the parameters (). When all 1-4 are commented above
--> The type DbConnection does not have an accessible constructor.
Unity Registration Code:
container.RegisterType<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>();
container.RegisterType<IRoleStore<IdentityRole>, RoleStore<IdentityRole>>();
container.RegisterType<AccountController>(new InjectionConstructor());
container.RegisterInstance(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ProjectEntities())));

Turn off data annotation validation for a property that is itself a view model, given a certain condition on the parent view model

I am constructing a page using Editor Templates and composition. My view model contains properties which are themselves view models. E.g.
public class ParentModel
{
public boolean SomeCheckBox { get; set; }
public ChildModel Child { get; set; }
}
public class ChildModel
{
[Required]
public string SomeString { get; set; }
[Required]
public string SomeOtherString { get; set; }
}
I would like the data annotation validation to kick in on the child only if the property SomeCheckBox on the parent is true.
I've seen a RequiredIf custom validation attribute elsewhere on stackoverflow, however it only works when the condition is a value of the same view model. I need something that can check the parent, or indeed a property on an ancestor.
My temporary hack is to clear the ModelState errors on postback if the checkbox isn't true.
I've also had to write some custom javascript so that the client browser suppresses the validation if the checkbox isn't ticked.
The real example is much more complicated than this but hopefully it's clear from the above simplified example what I'm after.
What would be nice is an attribute on the parent view model that is something like
public class ParentModel
{
public boolean SomeCheckBox { get; set; }
[SuppressValidationIf("SomeCheckBox", false)]
public ChildModel Child { get; set; }
}
Any ideas?
This excellent example perfectly illustrates the limitations of doing declarative validation which is what data annotations are.
It's for this reason that I would recommend you using an imperative approach for your validation rules as you can handle many scenarios. FluentValidation.NET is a great example of a library which would have rendered this validation scenario a piece of cake.
Let me illustrate how it could handle this scenario:
We start by defining validators for our child and parent models:
public class ChildModelValidator : AbstractValidator<ChildModel>
{
public ChildModelValidator()
{
RuleFor(x => x.SomeString).NotEmpty();
RuleFor(x => x.SomeOtherString).NotEmpty();
}
}
public class ParentModelValidator : AbstractValidator<ParentModel>
{
public ParentModelValidator()
{
RuleFor(x => x.Child)
.SetValidator(new ChildModelValidator())
.When(x => x.SomeCheckBox);
}
}
Notice how the child validator is included based on the value of the SomeCheckBox property on the parent? Now your models would look like this:
[Validator(typeof(ParentModelValidator))]
public class ParentModel
{
public bool SomeCheckBox { get; set; }
public ChildModel Child { get; set; }
}
public class ChildModel
{
public string SomeString { get; set; }
public string SomeOtherString { get; set; }
}
And that's all.
You simply install the FluentValidation.MVC3 NuGet, add the following line in Application_Start:
FluentValidationModelValidatorProvider.Configure();
and now you work as usual:
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new ParentModel
{
Child = new ChildModel()
});
}
[HttpPost]
public ActionResult Index(ParentModel model)
{
return View(model);
}
}
and a view:
#model ParentModel
#Html.ValidationSummary(false)
#using (Html.BeginForm())
{
#Html.CheckBoxFor(x => x.SomeCheckBox)
#Html.EditorFor(x => x.Child.SomeString)
#Html.EditorFor(x => x.Child.SomeOtherString)
<button type="submit">OK</button>
}
If the checkbox is checked the child validator will kick in and require the 2 properties.

Resources