I'm not sure the best way to get this accomplished. Here's my view:
public partial class MyPage : Page
{
[Import]
public MyVM ViewModel
{
get { return DataContext as MyVM ; }
set { DataContext = value; }
}
public String EventName { get; set; }
public MyPage()
{
InitializeComponent();
CompositionInitializer.SatisfyImports(this);
}
// Executes when the user navigates to this page.
protected override void OnNavigatedTo(NavigationEventArgs e)
{ }
}
And my VM:
[Export]
public class MyVM : ViewModelBase
{
public MyVM ()
{
}
}
This works great. However, I need to get data from either the viewmodel that has my string, or the URL. Either way, I'm not sure the best way to get the string to MyVW using MEF.
I thought ok I'll use Messaging from MVVMLight, but the MyVM class isn't instantiated yet to receive the broadcast from the other ViewModel. So then I thought well, I'll try this:
[Export]
public class MyVM : ViewModelBase
{
public MyVM ([Import("hello")]string hello)
{
}
}
and then put this in the view:
[Export("hello")]
public String MyHello { get; set; }
but that gave me an error. Cannot call SatisfyImports on a object of type 'Form A' because it is marked with one or more ExportAttributes.
So what's the best way to accomplish this?
To share data between views I usually inject a SharedData object into my ViewModels.
[Import(RequiredCreationPolicy = CreationPolicy.Shared)]
public ISharedData SharedData { get; set; }
I'm also using the Caliburn Micro framework so I'm not passing data around via the URL querystring. By convention CM will parse out URL parameters and inject them into properties on your VM but I'm not sure if this functionality only applies to Windows Phone development.
from here
Examine the Page’s QueryString. Look
for properties on the VM that match
the QueryString parameters and inject
them, performing the necessary type
coercion.
When you say you want to possibly pass data from the view to the vm, that should happen through databinding.
Related
I've created simple POCO class like this :
public class Entity
{
public int Id { get; set; }
public bool IsActive { get; set; }
}
And this is my EF DbContext :
public class SampleContext:DbContext
{
public DbSet<Entity> Entities { get; set; }
}
I defined sample logic layer like this :
public class EntityTask : IEntityTask
{
#region Implementation of IEntityTask
public IEnumerable<Entity> GetAll()
{
var contex = new SampleContext();
return contex.Entities.ToList();
}
#endregion
}
public interface IEntityTask
{
IEnumerable<Entity> GetAll();
}
This is DomainService class that defined in server project :
[EnableClientAccess()]
public class CrudService : DomainService
{
private readonly IEntityTask _entityTask;
public CrudService(IEntityTask entityTask)
{
_entityTask = entityTask;
}
public IQueryable<Entity> GetAll ()
{
return _entityTask.GetAll().AsQueryable();
}
}
After these steps I don't know how to bind data to DataGrid in silverlight project.
I've checked many links on the web but many of them use wizard to bind data to datagrid.
How do I bind entities to DataGrid ?
Start marking your entity with the KeyAttribute (probably on the Id property) then
you must indicate to msbuild how to create the proxy counterpart of your service (named the DomainContext): in your silverlight project under properties tab
select your "server side" project and build the solution.
Client side a proxy will be generated, check it by looking in the client project (be sure to press "Show all files in Solution Explorer" and look for something similar to the image below
Under the Generated_Code hidden folder you'll find your DomainContext.
From now on it should be pretty straightforward to load and bind your data. Look at the excellent blog posts series by Brad Abrams here, you'll find everything you need.
I use Castle Windsor bootstrapper in my WPF app. I tried register view model classes to windsor container.
I have all view models classes in namespace sample.viewmodels
So I tried this:
_windsorContainer.Register(AllTypes.FromAssembly(GetType().Assembly)
.Where(x => x.Namespace.EndsWith("ViewModels"))
.Configure(x => x.LifeStyle.Is(LifestyleType.Singleton)));
Or this way for register view model classes to container:
_windsorContainer.Register(AllTypes.FromAssembly(GetType().Assembly)
.Where(x => x.Namespace.Equals("Sample.ViewModels"))
.Configure(x => x.LifeStyle.Is(LifestyleType.Singleton)));
This way doesn't work. I don’t why. MainViewModel / ChildViewModel property is null.
If I use this style it works good.
////Shell
_windsorContainer.Register(
Component.For<IShellViewModel>()
.ImplementedBy<ShellViewModel>()
.LifeStyle.Is(LifestyleType.Singleton));
//Main screen
_windsorContainer.Register(
Component.For<IMainViewModel>()
.ImplementedBy<MainViewModel>()
.LifeStyle.Is(LifestyleType.Singleton));
//Child screen
_windsorContainer.Register(
Component.For<IChildViewModel>()
.ImplementedBy<ChildViewModel>()
.LifeStyle.Is(LifestyleType.Singleton));
What is bad in first case?
Here I have view models:
namespace Sample.ViewModels
{
public interface IShellViewModel
{}
public class ShellViewModel : Conductor<IScreen>.Collection.AllActive,
IShellViewModel
{
public IMainViewModel MainViewModel { get; set; }
public IChildViewModel ChildViewModel { get; set; }
protected override void OnInitialize()
{
DisplayName = "Castle Windsor Boostraper";
base.OnInitialize();
}
}
public interface IMainViewModel : IScreen
{
void SayHello();
}
public class MainViewModel : Screen, IMainViewModel
{
public void SayHello()
{
MessageBox.Show("Hello from MainViewModel");
}
}
public interface IChildViewModel : IScreen
{
void SayHello();
}
public class ChildViewModel : Screen, IChildViewModel
{
public void SayHello()
{
MessageBox.Show("Hello from ChildViewModel");
}
}
}
EDITED:
I little update registration part:
_windsorContainer.Register(AllTypes.FromAssembly(GetType().Assembly)
.Pick()
.WithService.DefaultInterface()
.Configure(x => x.LifeStyle.Is(LifestyleType.Singleton)));
It work but I am not sure if this is best way.
I think you want to do something like this to register your viewmodels in Castle Windosr
_windsorContainer.Register(AllTypes.FromThisAssembly()
.Where(x => x.Namespace.EndsWith("ViewModels"))
.WithService.AllInterfaces()
.WithService.Self()
.If(s => !s.IsAbstract)
.Configure(x => x.LifeStyle.Is(LifestyleType.Singleton)));
But I'm wondering why you register your viewmodels as singleton? I would register them as transient, so you could instanciate multiple different viewmodels for the same view in the application. I also use a marker-interface for my viewmodels, so I don't have to rely on the viewmodels on being in a namespace that ends with "ViewModels".
_windsorContainer.Register(Classes
.FromThisAssembly()
.BasedOn<IViewModelBase>()
.WithServiceAllInterfaces()
.WithServiceSelf()
.LifestyleTransient()
in the first example you are only registering the concrete types to be singletons, the second example you associate the relevant interfaces with the implementations. since your properties expose the models as interfaces, the first code part will not be able to satisfy those properties.
Edit:
I have found one method to do this but I'm not sure if it is the best way.
In WindsorContainer initialization, first I register viewmodel:
container.Register(Component.For<CentrosViewModel>().LifeStyle.Transient);
and later I register the View
container.Register(Component.For<CentrosAdminView>().LifeStyle.Transient.DependsOn(Property.ForKey("DataContext")
.Eq(ViewModelLocator.Centrosviewmodel)));
And definition of property ViewModelLocator.Centrosviewmodel is:
public static CentrosModel Centrosviewmodel
{
get
{
return App.container.Resolve<CentrosViewModel>();
}
}
End Edit
I'm trying to make an Wpf application using Castle Windsor and Mvvm Toolkit (galasoft) but I thing my problem will be the same with any MVVM toolkit.
With MVVM you must set the DataContext of the View to your ViewModel. Normally this is done by something like this in declaration of the view
DataContext={Binding MyViewModelInstanceName,Source={StaticResource Locator}}
Resource Locator is defined in App.xaml like this:
<Application.Resources>
<!--Global View Model Locator-->
<vm:ViewModelLocator x:Key="Locator" />
</Application.Resources>
If I establish StartupURI in App.xaml to my view all is right.
But if I leave StartupUri blank and I try to get an instance of my view through castle using following syntax:
container.Resolve<CentrosAdminView>().Show();
I get exception: "Cannot Find Resource with Name '{Locator}'
I supose that Initial DataContext is different when running directly than when running through Castle Windsor and this is the reason why it can't find resource.
My two questions are:
Is It necessary have a ViewModelLocator when using Castle Windsor? In
case of Yes: How can I setup DataContext of Views correctly with
Windsor? In case of No: How would be the right way?
I leave down my Castle Configuration. Any help would be really appreciated.
My Windsor configuration look like this:
<castle>
<properties>
<!-- SQL Server settings -->
<connectionString>Server=192.168.69.69;Database=GIOFACTMVVM;user id=sa;password=22336655</connectionString>
<nhibernateDriver>NHibernate.Driver.SqlClientDriver</nhibernateDriver>
<nhibernateDialect>NHibernate.Dialect.MsSql2005Dialect</nhibernateDialect>
</properties>
<facilities>
<facility id="nhibernatefacility"
type="Repository.Infrastructure.ContextualNHibernateFacility, Repository">
<factory id="sessionFactory1">
<settings>
<item key="connection.provider">NHibernate.Connection.DriverConnectionProvider</item>
<item key="connection.driver_class">#{nhibernateDriver}</item>
<item key="connection.connection_string">#{connectionString}</item>
<item key="dialect">#{nhibernateDialect}</item>
<item key="proxyfactory.factory_class">NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle</item>
</settings>
<assemblies>
<assembly>Domain</assembly>
<assembly>ObservableCollections</assembly>
</assemblies>
</factory>
</facility>
</facilities>
</castle>
and by code:
public static IWindsorContainer Start()
{
var container = new WindsorContainer(new XmlInterpreter());
container.AddFacility<TransactionFacility>();
container.Register(
Component.For<HistoriasAdminView>().LifeStyle.Transient,
Component.For<HistoriasModel>().LifeStyle.Transient,
Component.For<CentrosModel>().LifeStyle.Transient,
Component.For<CentrosAdminView>().LifeStyle.Transient,
Component.For<MainViewModel>().LifeStyle.Transient,
Component.For<MainWindow>().LifeStyle.Transient,
Component.For<IRepository<Historias>>().ImplementedBy<Repository<Historias>>().LifeStyle.Transient,
Component.For<IRepository<Centros>>().ImplementedBy<Repository<Centros>>().LifeStyle.Transient,
Component.For<IUnitOfWork>().ImplementedBy<NHUnitOfWork>().LifeStyle.Transient
);
return container;
}
You are using the Service Locator pattern, where you register services, pass around a reference to the container, and explicitly call resolve all over you code. If you take a quick tour through the Castle Windsor wiki, they discourage this use of the container.
Generally, you should register all your types (via installers), resolve only one root object (maybe your main view, maybe some sort of startup/MVC controller style code), and let the rest be resolved by the container. The next time you will call the container will almost always be container.Dispose, when your application exits.
See the Windsor wiki page regarding the Three Calls Pattern.
If you find cases where you need to pull from the container during runtime to create specific instances (where you have to pass specific parameters to create that instance), use the Typed Factory Facility instead of directly resolving dependencies.
MVVM with Windsor:
In my first MVVM app I wrote with Windsor (just finished the first version), I simply registered my main view and view model without specifying the lifestyle. This defaulted them to be singletons.
The view took a view model instance as a required dependency (in the constructor), and used it to set the data context. I did this in code-behind because it was non-intrusive and painless.
// In my program I used interfaces for everything. You don't actually have to...
public interface IMainView
{
void Show();
}
public class MainView : Window, IMainView
{
public MainView(IMainViewModel viewModel)
{
Initialize();
this.DataContext = viewModel;
}
}
public interface IMainViewModel
{
int SomeProperty { get; set; }
ICommand ShowSubViewCommand { get; }
// ...
}
public class MainViewModel : IMainViewModel
{
public MainViewModel(SomeOtherSubComponent subComponent)
{
this.subComponent = subComponent;
// ...
}
// ...
}
Where I had sub-views that I wanted to create multiple instances of, I registered them with a transient life-cycle. Then I created a view factory and view model factory, and used them to get instances of the sub-view and sub-viewmodel from the parent view. I registered an event handler for the view's close event, and called a Release method on the factory classes.
public interface ISubView
{
void Show();
event Action OnDismissed;
}
public class SubView : Window, ISubView
{
public SubView(ISubViewModel viewModel)
{
Initialize();
this.DataContext = viewModel;
// Would do this in the view model,
// but it is a pain to get Window.Close to call an ICommand, ala MVVM
this.OnClose += (s, a) => RaiseDismissed();
}
public event Action OnDismissed;
private void RaiseDismissed()
{
if(OnDismissed != null)
OnDismissed();
}
}
public interface ISubViewModel
{
string SomeProperty { get; }
// ...
}
// Need to create instances on the fly, so using Typed Factory facility.
// The facility implements them, so we don't have to :)
public interface IViewFactory
{
ISubView GetSubView(ISubViewModel viewModel);
void Release(ISubView view);
}
public interface IViewModelFactory
{
ISubViewModel GetSubViewModel();
void Release(ISubViewModel viewModel);
}
// Editing the earlier class for an example...
public class MainViewModel : IMainViewModel
{
public MainViewModel(IViewFactory viewFactory, IViewModelFactory viewModelFactory)
{
this.viewFactory = viewFactory;
this.viewModelFactory = viewModelFactory;
// Todo: Wire up ShowSubViewCommand to call CreateSubView here in ctor
}
public ICommand ShowSubViewCommand { get; private set; }
private void CreateSubView()
{
var viewModel = viewModelFactory.GetSubViewModel();
var view = viewFactory.GetSubView(viewModel);
view.OnDismissed += () =>
{
viewModelFactory.Release(viewModel);
viewFactory.Release(view);
};
view.Show();
}
// Other code, private state, etc...
}
At the end of all this, the only calls to the container are:
void App_Startup()
{
this.container = new WindsorContainer();
container.Install(Configuration.FromAppConfig());
var mainView = container.Resolve<IMainView>();
mainView.Show();
}
public override OnExit()
{
container.Dispose();
}
The benefit to all this rigmarole is that it is independent of the container (and can be used without a container), it is obvious which dependencies each of my components take, and most of my code doesn't ever have to ask for its dependencies. The dependencies are just handed to each component as it needs it.
I have a WPF windows application that uses the ms ribbon control for the menu. In my infrastructure project I want to have a shared service that will be referenced in all modules. Each module will then use that service to define what menu items should be displayed for the module.
I read this Prism+MEF: delayed a service export from prism-module but can't get my other modules to recognize the service.
The service
namespace Infrastructure
{
[ModuleExport("InfModule", typeof(InfModule), InitializationMode = InitializationMode.WhenAvailable)]
[PartCreationPolicy(CreationPolicy.Shared)]
public class InfModule : IModule
{
[Export(typeof(IMenuService))]
public IMenuService MenuService { get; private set; }
public void Initialize()
{
MenuService = new MenuService();
MenuService.AddItem("test");
}
}
}
The module
namespace Classic
{
[ModuleExport("Classic", typeof(Classic), InitializationMode = InitializationMode.WhenAvailable)]
[ModuleDependency("InfModule")]
public class Classic : IModule
{
private IRegionManager _regionManager;
[Import(typeof(IMenuService))]
private IMenuService menuService { get; set; }
[ImportingConstructor]
public Classic(IRegionManager regionManager)
{
this._regionManager = regionManager;
// This shows as true
Debug.WriteLine(menuService == null);
}
public void Initialize()
{
_regionManager.RegisterViewWithRegion("RibbonRegion", typeof(Views.RibbonTabMenu));
// This shows as true
Debug.WriteLine(menuService == null);
}
}
}
I would have expected one of the debug lines to output as false since its imported. Any idea's what I'm missing?
Property imports will never be set while running the constructor, since you can't set properties on an object until it's constructed.
The other problem is that in InfModule, you are setting the exported value too late. MEF only looks at the value for an export once, after that it caches the value and doesn't call the getter again. In this case it is getting the export before Initialize() is called. The logic to set the export needs to either run from the constructor or from code in the property getter.
I'm currently trying to create a small application using the MVVM pattern. However I don't really know how to correctly wrap up aggregated Model classes in my ViewModel. From what little I know about MVVM, you're not supposed to expose Models in your ViewModel as properties or else you could directly bind to the Model from your View. So it seems I have to wrap the nested Model in another ViewModel, but this imposes some problems while synching Model and ViewModel later on.
So how do you do that efficiently?
I'll give a short example. Let's suppose I have the following model classes:
public class Bar
{
public string Name { get; set; }
}
public class Foo
{
public Bar NestedBar { get; set; }
}
Now I create two ViewModel classes accordingly, wrapping the Models, but run into problems with the FooViewModel:
public class BarViewModel
{
private Bar _bar;
public string Name
{
get { return _bar.Name; }
set { _bar.Name = value; }
}
}
public class FooViewModel
{
private Foo _foo;
public BarViewModel Bar
{
get { return ???; }
set { ??? = value; }
}
}
Now what do I do with the Bar-property of FooViewModel? For "get" to work I need to return a BarViewModel instance. Do I create a new field of that type in FooViewModel and just wrap the _foo.NestedBar object in there? Changes to that field's properties should propagate down to the underlying Bar instance, right?
What if I need to assign another BarViewModel instance to that property, like so:
foo.Bar = new BarViewModel();
Now that won't propagate down to the model, which still holds the old instance of type Bar. I'd need to create a new Bar object based on the new BarViewModel and assing it to _foo, but how do you do that elegantly? It's pretty trivial in this sample, but if Bar is much more complex with lots of properties, that'll be a lot of typing... not to mention it'd be very prone to errors, if you forget to set one of the properties.
#Goblin
There are some flaws with your code: e.g. what if I get a list of Foo objects from database and I want to wrap each of them in an ObservableCollection?
then your Constructor of FooViewModel should accept the Foo model as parameter and not create it inside the Constructor!
Normally you do this to wrap a model into a viewmodel and put it the same time into a bindable Collection:
IEnumerable<Foo> foos = fooRepository.GetFoos();
foos.Select( m => viewmodelCollection.Add(new ViewModel(m,e.g.Service)));
The models properties are not copied to the ViewModel hell no!!! The ViewModel does delegate its properties to the model properties like:
public class FooViewModel
{
private Foo _foo;
public FooViewModel(Foo foo,IService service)
{
_foo = foo;
}
public string FoosName
{
get{return _foo.Name };
set
{
if(_foo.Name == value)
return;
_foo.Name = value;
this.NotifyPropertyChanged("FoosName");
}
}
}
And like Goblin said all UI-Specific interfaces like:
IDataErrorInfo
INotifyPropertyChanged
IEditableObject
etc...
are implemented the by the ViewModel ONLY.
My above answer only makes sense if you are doing DDD - if you are not - you can solve your problem like this - simply 'flattening' the model:
public class FooViewModel
{
private Foo _foo;
public string Name
{
get { return _foo.Name; }
set { _foo.Name = value; }
}
public string BarProperty
{
get { return _foo.Bar.Property; }
set { _foo.Bar.Property = value; }
}
}
Or you could do like I showed in the prior example - just ignore everything about Aggregates... should still work.
Okay - first things first - using the term Aggregate implies you are adhering to DDD? If you are - you are doing an encapsulation no-no :-). One Aggregate should never be allowed to edit another Aggregate. If what you have is that both are really Aggregate they would become associated (which is perfectly 'legal' in a DDD-sense - but then your propety on the FooViewModel wouldn't be of type BarViewModel, but rather type Bar. That way Bar would (as it should) be responsible for updating itself - and we only maintain the link in FooViewModel.
However, if what you are doing is AggregateRoot with a ValueType child - then here is what you could do given a slightly modified domain model:
public class Foo
{
public string SomeProperty { get; set; }
public Bar Bar { get; set; }
public void Save()
{
//Magically saves to persistent storage...
}
}
public class Bar
{
public Bar(string someOtherProperty)
{
SomeOtherProperty = someOtherProperty;
}
public string SomeOtherProperty { get; private set; }
}
And then for the ViewModels:
public class FooViewModel
{
private Foo _foo;
public FooViewModel()
{
Bar = new BarViewModel();
}
public BarViewModel Bar { get; private set; }
public void SetFoo(Foo foo)
{
_foo = foo;
SomeProperty = foo.SomeProperty;
Bar.SetBar(foo.Bar);
}
public string SomeProperty { get; set; }
public void SaveChanges()
{
_foo.SomeProperty = SomeProperty;
_foo.Bar = Bar.CreateUpdatedBar();
_foo.Save();
}
}
public class BarViewModel
{
public string SomeOtherProperty { get; set; }
public void SetBar(Bar bar)
{
SomeOtherProperty = bar.SomeOtherProperty;
}
public Bar CreateUpdatedBar()
{
return new Bar(SomeOtherProperty);
}
}
This way - the FooViewModel is now capable of controlling the BarViewModel (which does nothing but accept a valuetype - and create a new one when asked). This also solves a common UI-problem ('How do we edit an object that has no setters?' - answer: 'We don't - we create a new one'). A lot of fleshing out is missing (INotifyPropertyChanged, dirty-tracking etc., but those are easy if you get through this leap of thinking :-).
I hope this makes a wee bit of sense :-) Otherwise, I'll be happy to elaborate.