I'm using MVVM Light, MahApps and SimpleChildWindows.
I want to be able to create a CRUD Form in a modal popup.
This CRUD form must be binded to its own ViewModel and called by a command in another ViewModel.
I don't succeed to do this with SimpleChildWindows...
So... Is it possible?
How I solved similar problem for myself, taking advantage of Dependency Injection:
I used Unity and registered dependency to 'Func':
public partial class App
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
IUnityContainer container = new UnityContainer();
container.RegisterType<EntityCRUDWindowViewModel>();
container.RegisterType<ConsumerViewModel>();
container.RegisterInstance<Func<Entity, EntityCRUDWindow>>(entity => new EntityCRUDWindow(){DataContext=container.Resolve<EntityCRUDWindowViewModel>(new ParameterOverride("entity", new InjectionParameter<Entity>(entity))));
/* whatever goes here */
}
}
ViewModel for the CRUD window looks like
public class EntityCRUDWindowViewModel
{
private readonly Entity entity;
public EntityCRUDWindowViewModel(Entity entity)
{
this.entity = entity;
}
}
and you can get the instance of window EntityCRUDWindow
and use it in ConsumerViewModel
or any other ViewModel by simply declaring in constructor parameter
public class ConsumerViewModel
{
public ConsumerViewModel(Func<Entity, EntityCRUDWindow> entityCrudWindowFactory)
{
this.WhateverCommand = new DelegateCommand(
() =>
{
Entity someEntity = null; //or whatever
entityCrudWindowFactory(someEntity).ShowDialog();
});
}
public ICommand WhateverCommand { get; }
}
Thus, you can put any dependency you need in constructor parameters of both viewmodels, just keeping in mind that Entity entity
parameter must be present in EntityCRUDWindowViewModel
.
I would probably add DataTemplate to resources and that will render whenever you bind Content to some CrudViewModelType instance
<Grid>
<Grid.Resources>
<DataTemplate DataType="{x:Type whateverNs:MyCrudViewModelType}">
<UserControl Content="{Binding}"/>
</DataTemplate>
</Grid.Resources>
<ContentControl Content={Binding CurrentCrudViewModel}></ContentControl>
<simpleChildWindow:ChildWindow IsOpen="{Binding OpenChildWindows}" Content="{Binding MyCrudViewModel}"/>
</Grid>
Ok sometimes the solution is under my nose but I struggle to see it...
So here is my solution:
<Grid>
<Grid >
<UserControl Content="{Binding Path=CurrentViewModel}"/>
</Grid>
<simpleChildWindow:ChildWindow IsOpen="{Binding OpenChildWindows}"
Title="{Binding TitleChildWindows}"
Content="{Binding CurrentWindowsViewModel }"/>
</Grid>
The CurrentWindowsViewModel is binded to a UserControl which fits perfectly in the Content property of my SimpleChildWindows.
However I must Bind all the ChildWindows properties to the Viewmodel which "Host" my childwindows ("Title", "IsOpen" etc).
All the ChildWindows ViewModel inherit from a class Template (which obviously inherits from ViewModelBase) with a Title and maybe some others properties specific to ChildWindows.
I communicate through the MVVM light Messenger to tell the "Host" which ViewModel to display by its name and then I read its"Title" and open the Windows by the "IsOpen" propertie:
private void ReceiveMessage(EnumViewModelNames viewName)
{
var selectedViewModel = ViewModelList.Where(x => x.ViewModelName == viewName).SingleOrDefault();
if (selectedViewModel is TemplateWindowsViewModel)
{
TitleChildWindows = (selectedViewModel as TemplateWindowsViewModel).Title;
OpenChildWindows = true;
CurrentWindowsViewModel = (selectedViewModel as TemplateWindowsViewModel);
}
else if (selectedViewModel != null)
{
CurrentViewModel = selectedViewModel;
}
Messenger.Default.Unregister<EnumViewModelNames>(this, (action) => ReceiveMessage(action));
}
This way, I'm able to open the childWindows from the "CurrentViewModel", or the "MainViewModel".
It works pretty well and the view is simply a standard Usercontrol binded to a DataContext in the ViewModelLocator.
Sorry Heorhiy Pavlovych, I've seen that you were trying hard, but we misunderstood...