while reading this tutorial at
http://www.codeproject.com/Articles/380215/Understanding-MVP-WCSF-Over-ASP-NET-Web-Forms?msg=4970179#xx4970179xx
I find the attribute [CreateNew] used with property Presenter
protected void Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack)
{
this._presenter.OnViewInitialized();
}
this._presenter.OnViewLoaded();
}
[CreateNew]
public ProductPresenter Presenter
{
get
{
return this._presenter;
}
set
{
if (value == null)
throw new ArgumentNullException("value");
this._presenter = value;
this._presenter.View = this;
}
}
and here it is used before method parameter
private IProductsController _controller;
public ProductPresenter([CreateNew] IProductsController controller)
{
//// Method on controller class invoked here
_controller = controller;
}
What does the attribute [CreateNew] meand before property and what does it mean when used with the method parameter? Thanks.
I got the answer. Here it is. [CreateNew] is used to create new object for dependency
injection
Dependency Injection and the Composite Application Block (Introduction to CAB/SCSF Part 5)
It is part of the Composite Application Block and here is a good in fact a very good tutorial introducing the Composite Application Block and Smart Client Software Factory - Introduction to CAB/SCSF.
And here is the link for tutorial table of contents for all tutorial parts
Table of Contents: Introduction to CAB/SCSF
Related
I Am very new to Caliburn and have to expand an existing program, using caliburn.micro
I need my DataContext in a View to be set to a ViewModel which has some propertyinjected parameters. All this should work, so i only need to build it up.
however it does not! here is the code where i try to bulid:
public ProductionMainView()
{
InitializeComponent();
var gg = IoC.Get<ProductionMainViewModel>();
IoC.BuildUp(gg);
this.DataContext = gg;
}
As far as i can understand I need to get the object and then build it.
Now I should get a view "Containing" my ViewModel, but the View is blank,
I hope i have explained myself well enough.
Best regards
First off you are using a really old version, present version is 2.0.2, and you still need to have overrides for GetInstance, GetAllInstances, BuildUp methods in your BootStrapper or a variant for use with Ninject
http://putridparrot.com/blog/caliburn-micro-and-inversion-of-control-using-ninject/
Link above has some source for this.
Remember there is nearly no code in the Codebehind of the View... It will all go into the ViewModels (for the most part). ShellView => ShellViewModel with in ShellViewModel var gg = IoC.Get<ProductViewModel>() depending on you are intent is with that you can bind it to a <ContentControl x:Name="ProductViewModel" /> with a property in yoru viewmodel called exactly that. CM will go out and fine that ViewModel and associated view and mash them together automagically. Expected results on the screen should be your ProductViewModel in that contentcontrol location.
public class ShellViewModel : Screen
{
private ProductViewModel _productViewModel;
public ShellViewModel (){
}
protected override void OnActivate(){
ProductViewModel = IoC.Get<ProductViewModel>();
}
public ProductViewModel ProductViewModel {
get{ return _productViewModel;}
set{
_productViewModel = value;
NotifyOfPropertyChanged (); // 2.0.2 feature...
}
}
}
Now, if you decide to move to the latest version there are subtle changes one Bootstrapper<T> does not exist anymore it was refactored into BootstrapperBase. Next Initialize() will be placed into the ctor of your Bootstrapper(). From there everything will be based on your starting screen is after Initialize() is called in the CTOR you will call DisplayRootViewFor<ShellViewModel>() in the OnStartup override.
Some have said and I tend to agree over using IoC.Get<T>() can be anti-pattern, caution when using it. Sometimes things change unexpectedly. Those tend to DI the items via the CTOR and use from there accordingly.
/*version 1.52*/
public class Bootstrapper : BootStrapper<LoginViewModel>{
public Bootstrapper(){
Start();
}
protected override Configure(){
/* -- your Ninject configurations -- */
}
protected override object GetInstance(Type service, string Key){
if(service == null)
throw new ArgumentNullException("Service");
return _kernel.Get(service);
}
protected override IEnumerable<object> GetAllInstances(Type service){
return _kernel.GetAll(service);
}
protected override void BuildUp(object instance){
_kernel.Inject(instance);
}
protected override void OnExit(object sender, EventArgs e)
{
kernel.Dispose();
base.OnExit(sender, e);
}
}
To clarify do you have to login to get to the ProductionMainViewModel? What determines your logic for getting to ProductionMainViewModel to even display?
I am using MvvmCross' IoC property injection, initialized in my respective Setup.cs-classes:
protected override IMvxIocOptions CreateIocOptions()
{
return new MvxIocOptions {
PropertyInjectorOptions = MvxPropertyInjectorOptions.All
};
}
In my view models I then have several public interface properties like this:
public void IDataService DataService { get; set; }
Everything works when I run the app, but the unit tests fail because DataService is null.
How can I set up property injection correctly when using MvxIoCSupportingTest?
Got it working based on Stuart's answer, which I had to modify to avoid private fields and methods:
protected new IMvxIoCProvider Ioc { get; private set; }
protected override void ClearAll()
{
// fake set up of the IoC
MvxSingleton.ClearAllSingletons();
var iocOptions = new MvxIocOptions {
PropertyInjectorOptions = MvxPropertyInjectorOptions.All
};
Ioc = MvxSimpleIoCContainer.Initialize(iocOptions);
Ioc.RegisterSingleton(Ioc);
Ioc.RegisterSingleton<IMvxTrace>(new TestTrace());
MvxSingletonCache.Initialize();
Ioc.RegisterSingleton<IMvxSettings>(new MvxSettings());
MvxTrace.Initialize();
AdditionalSetup();
}
I also submitted a pull request for overriding CreateIocOptions directly, which would make it easier: https://github.com/MvvmCross/MvvmCross/pull/897/files
To override the Ioc options used in MvxIoCSupportingTest, you'll need to override ClearAll():
protected override void ClearAll()
{
// fake set up of the IoC
MvxSingleton.ClearAllSingletons();
_ioc = MvxSimpleIoCContainer.Initialize(/* YOUR OPTIONS HERE */);
_ioc.RegisterSingleton(_ioc);
_ioc.RegisterSingleton<IMvxTrace>(new TestTrace());
InitializeSingletonCache();
InitializeMvxSettings();
MvxTrace.Initialize();
AdditionalSetup();
}
from https://github.com/MvvmCross/MvvmCross/blob/3.5/Cirrious/Test/Cirrious.MvvmCross.Test.Core/MvxIoCSupportingTest.cs#L33
It would definitely be nicer if that Test class had a CreateIoCOptions() virtual method instead.
It must be showing error:
Failed to construct and initialize ViewModel for type Viewmodel. You might be missing :
public override void Initialize() {
CreatableTypes()
.EndingWith("Service")
.AsTypes()
.RegisterAsSingleton();
}
For detailed reference you can check out following link.
https://stackoverflow.com/a/18946672/4373895
Hope this helps you.
I am using MVVM Light and I'm currently using SimpleIoC that comes with the package. I'm getting a bit stuck with the dependency injection. I have a bunch of services that I want to use in my view models, however most windows are a List-Edit paradigm, i.e. one screen lists all of type Person and then you can Add or Edit a Person via a new screen.
When I was doing all code in the code behind my code for adding and editing a record was as follows:
View
private void btnEdit_Click(object sender, RoutedEventArgs e)
{
_viewModel.Edit();
}
private void btnAdd_Click(object sender, RoutedEventArgs e)
{
_viewModel.Add();
}
View Model
public void Add()
{
var f = new TypeDetails();
f.Show();
}
public void Edit()
{
if (SelectedItem == null)
return;
var f = new TypeDetails(SelectedItem.Id);
f.Show();
}
The constructor of TypeDetails is as follows:
public TypeDetails(int id = 0)
{
InitializeComponent();
_viewModel = new TypeDetailsViewModel(id);
DataContext = _viewModel;
}
What would the best be to implement this type functionality with MVVM Light? I have been using the ViewModelLocator class for the List screens, however I cannot see a way to do this using the SimpleIoC. My way round so far has been to keep the constructor the same, which works fine until I need to inject dependencies into the TypeDetailsViewModel such as a service. With a service the constructor of TypeDetailsViewModel would be:
public TypeDetailsViewModel(ISomeService someService, int id = 0)
{
...
}
But that means in my view constructor I have to build these dependencies one at a time and manually inject them...
public TypeDetails(int id = 0)
{
InitializeComponent();
_viewModel = new TypeDetailsViewModel(SimpleIoC.Current.GetInstance<ISomeService>(),id);
DataContext = _viewModel;
}
Is there a better way to do this?
First off I would look into the "RelayCommand" class which is part of MVVM Light. It will remove the need for events in your code behind. Start with that.
You should always favor "Constructor Injection" instead of the ServiceLocator (ex: SimpleIoC.Current.GetInstance())
Your ViewModel constructor should only be injecting services and not primitive types like "int". In your example "int id" should be the parameter of a method and not injected.
Ex: Instead, your TypeDetailsViewModel should look more like:
public TypeDetailsViewModel(ISomeService someService)
{
TypeDetail GetDetailsCommand(int id)
{
...
}
}
Lastly, your Models should never have any reference to your ViewModels.
For your DataContext, you can use a ViewModelLocator (ViewModels in ViewModelLocator MVVM Light)
To hook up your View and ViewModel to use the GetDetailsCommand, you can use the EventToCommand behavior (http://msdn.microsoft.com/en-us/magazine/dn237302.aspx). Ex: The OnLoaded event on the View calls the GetDetailsCommand on your ViewModel.
Injecting dependencies in Global.asax does not seem to always work. Sometimes it does, sometimes I get a ContextDisposedException (it seems that the problem occurs when I'm doing a Page.Redirect ??). I'm in an ASP.NET WebForm context.
Here is my code:
public class Global : HttpApplication
{
[Inject]
public UserManager UserManager { get; set; }
private void Application_PostAuthenticateRequest(object sender, EventArgs e)
{
if (User.Identity.IsAuthenticated)
{
GlobalSecurityContext.SetPrincipal(User);
string path = Request.AppRelativeCurrentExecutionFilePath;
if (path.Contains(".aspx"))
{
// Get the current user
var userData = UserManager.GetByIdWithLogin(User.Identity.Name);
if (userData != null)
{
LoginDataDTO data = userData.LoginData;
if (data.XXX && ...)
{
Response.Redirect(...);
}
}
}
}
}
protected void Session_End(Object sender, EventArgs e)
{
UserManager.Logout();
}
}
In this post How to inject dependencies into the global.asax.cs, Mark Seemann says that one should not use Dependency Injection in global.asax because global.asax IS the Composition Root.
So what is the best way to solve my problem since I don't want to directly call my UserManager because the constructor needs a repository
public UserManager(IGenericRepository repository) : base(repository)
{
}
and the GenericRepository has itself a constructor that needs a IContext
public GenericRepository(IContext context)
{
}
I could probably do new UserManager(new GenericRepository(new MyContext)) but
I will not reuse the same context for the whole request
I need to add a reference on my AccessLayer in the GUI, what I would like to avoid
Just as an information, currently I'm injecting the Context like this:
// Dynamically load the context so that we dont have a direct reference on it!
string contextType = // read type from web.config
if (!String.IsNullOrEmpty(contextType))
{
Type context = Type.GetType(contextType);
Bind<IContext>().To(context).InRequestScope();
}
Any help would be greatly appreciated !
[Edit]:
Changing the UserProperty property like this works:
public UserManager UserManager
{
get { return ServiceLocator.Current.GetInstance<UserManager>(); }
}
In this case you can build your Ninject container, and use it a Service Locator for this particular instance (since you're in the Composition Root - you can't inject anything at this point).
Have been learning about MVP and have tried writing a test app using it in WinForms. I'm struggling to find a well explained example on how to navigate between my forms/views. As an example, the program starts and I want to show a login dialog then go into my main view if the login was successful. At the moment, my Main method looks something like this:
static void Main()
{
var loginView = Injector.Resolve<ILoginView>();
if (loginView.DoLogin() != LoginResult.OK) return;
var mainView = Injector.Resolve<IMainView>();
Application.Run(mainView); // won't work as mainView isn't a form
}
The Injector object is just a wrapper around an IoC tool (currently StructureMap). The thing is, I've read that I shouldn't really be manually creating instances via the Injector as they should really be done via constructor injection.
I've managed to do this up to a point but not when it comes to navigation. I can't think of an elegant way of moving through my views and was wondering if anyone here might shed some light on this? I've read a little on application controllers but have not found an example to show it clearly.
In regards to the navigation question:
I've managed to do this up to a point but not when it comes to
navigation. I can't think of an elegant way of moving through my views
and was wondering if anyone here might shed some light on this? I've
read a little on application controllers but have not found an example
to show it clearly.
Below is a simplified version of a construct I've used. Note that the setup and tear down hooks are called automatically when the NavigateTo method is called. Also, +1 to #AlexBurtsev, as his answer hints at this very same approach.
// Presenter can and should offer common services for the
// subclasses
abstract class Presenter
{
public void Display()
{
OnDisplay();
}
public void Dismiss()
{
OnDismiss();
}
protected virtual OnDisplay() // hook for subclass
{
}
protected virtual OnDismiss() // hook for subclass
{
}
private NavigationManager _navMgr;
internal NavigationMgr NavigationManager
{
get
{
return _navMgr;
}
set
{
_navMgr = value;
}
}
}
// NavigationManager is used to transition (or navigate)
// between views
class NavigationManager
{
Presenter _current;
// use this override if your Presenter are non-persistent (transient)
public void NavigateTo(Type nextPresenterType, object args)
{
Presenter nextPresenter = Activator.CreateInstance(nextPresenterType);
NavigateTo(nextPresenter);
}
// use this override if your Presenter are persistent (long-lived)
public void NavigateTo(Presenter nextPresenter, object args)
{
if (_current != null)
{
_current.Dismiss()
_current.NavigationMgr = null;
_current = null;
}
if (nextPresenter != null)
{
_current = nextPresenter;
_current.NavigationMgr = this;
_current.Display(args);
}
}
}
class MainMenuPresenter : Presenter
{
private IMainMenuView _mainMenuView = null;
// OnDisplay is your startup hook
protected override void OnDisplay()
{
// get your view from where ever (injection, etc)
_mainMenuView = GetView();
// configure your view
_mainMenuView.Title = GetMainTitleInCurrentLanguage();
// etc
// etc
// listen for relevent events from the view
_mainMenuView.NewWorkOrderSelected += new EventHandler(MainMenuView_NewWorkOrderSelected);
// display to the user
_mainMenuView.Show();
}
protected override void OnDismiss()
{
// cleanup
_mainMenuView.NewWorkOrderSelected -= new EventHandler(MainMenuView_NewWorkOrderSelected);
_mainMenuView.Close();
_mainMenuView = null;
}
// respond to the various view events
private void MainMenuView_NewWorkOrderSelected(object src, EventArgs e)
{
// example of transitioning to a new view here...
NavigationMgr.NavigateTo(NewWorkOrderPresenter, null);
}
}
class NewWorkOrderPresenter : Presenter
{
protected override void OnDisplay()
{
// get the view, configure it, listen for its events, and show it
}
protected override void OnDismiss()
{
// unlisten for events and release the view
}
}
I haven't used WinForms for a long time, but I'll try to answer this. I would use the same strategy as WPF Prism do.
About MainView and Application.Run:
Create a main Region (root Form), with empty container inside which can hold UserControl (I forgot exact class names), then when you need to switch root view, you do RootView.SetView(UserControl view) which will do something like Form.Clear(), Form.AddChild(view).
About the navigation and using container:
You could create a service for navigation: INavigationService which you inject in constructors with method like INavigationService.NavigateView(String(or Type) viewName, params object[] additionalData)
You can insert a method in mainView that returns the actual form.Then you can call
Mainview:IMainView
{
Form GetView()
{
//return new Form();
}
}
In Main you can call ,
Application.Run(mainView.GetView())