As i title suggests, i want to know what is the best and simplest method to create window from ViewModel in MVVM pattern.
-
Create a window service that you inject the view model with: https://stackoverflow.com/questions/47352870/mvvm-show-new-window-from-vm-when-seperated-projects/47353136#47353136 – mm8 Jun 15 '21 at 14:42
1 Answers
i want to know what is the best and simplest method to create window from ViewModel in MVVM pattern
"The best", "the simplest" are very subjective concepts.
For some, a simple implementation may be considered difficult by someone.
This topic is very large, and for a detailed answer to such a question, you will need to write a thick textbook.
Therefore, in short, general concepts, and an example of a possible implementation.
From the ViewModel's point of view, it cannot "know" what a Window is. So asking the question "How should a VM create a Window?" - it is not correct.
The question should be asked like this: "How does the VM call an external dialogue?".
How this dialog will be implemented (WPF Window, Form or Console Input) for the VM does not matter.
A dialog is, in fact, a delegate to a method that returns a dialog result.
In the simplest case, the diaolog's result is just a bool (success / failure).
Let's say OpenFileDialog.ShowDialog returns Nullable <bool>
.
In more complex cases, an enumeration is returned. Sample MessageBox.
What kind of dialogue result you need depends on the conditions of your task.
Suppose if this is an element editing dialog, then it receives an element for editing in its parameters, and it can return bool: true - editing is completed and its results need to be saved, false - editing cancellation.
Gets the ViewModel delegate, usually at the time of its creation.
This is called dependency injection.
A typical place for Dependency Injection is App.
An example will link to your previous topic WPF MVVM binding command to Datacontext inside Datagrid
using System;
using System.Collections.ObjectModel;
namespace MoldsApp
{
public class MainWindowViewModel
{
//A collection-property of type ObservableCollection is best implemented as «ReadOnly».
public ObservableCollection<Molds> AllMolds { get; }
private readonly Func<Molds, bool> editDialog;
// Constructor receiving dialog delegate
public MainWindowViewModel(Func<Molds, bool> editDialog)
{
this.editDialog = editDialog;
}
private LamdaCommand _editCommand;
public LamdaCommand EditCommand => _editCommand
?? (_editCommand = new LamdaCommand(EditExecute, EditCanExecute));
private bool EditCanExecute(object parameter)
=> parameter is Molds;
private void EditExecute(object parameter)
{
Molds molds = (Molds)parameter;
// At this point, there should be element preprocessing code.
// Let's say copying for the possibility of canceling the result of editing.
Molds moldsCopy = molds.Copy();
// Calling a dialog and getting its result
var result = editDialog(moldsCopy);
if (result)
{
// Saving the result.
// And changing the item to match the edited copy.
Save(moldsCopy);
molds.CopyValuesFrom(moldsCopy);
}
}
private void Save(Molds moldsCopy)
{
throw new NotImplementedException();
}
}
}
MainWindowViewModel Instance will be instantiated in App. In order for the Window to get it into its DataContext, it is convenient to set it in the App resources. To do this, let's make a simple container-class:
public class Locator
{
public MainWindowViewModel MainVM { get; set; }
}
<Application ----------
----------
StartupUri="MainWindow.xaml"
Startup="OnStartup">
<Application.Resources>
<moldsapp:Locator x:Key="locator"/>
</Application.Resources>
</Application>
Now, in the App Code Behind, we initialize all this:
public partial class App : Application
{
private void OnStartup(object sender, StartupEventArgs e)
{
Locator locator = (Locator) Resources["locator"];
locator.MainVM = new MainWindowViewModel(MoldsEditHandler);
}
private static bool MoldsEditHandler(Molds molds)
{
AddEditWindow window = new AddEditWindow()
{
DataContext = new AddEditWindowViewModel(molds)
};
var result = window.ShowDialog();
return result == true;
}
}
In the Main Window, we set getting the DataContext from the locator:
<Window ---------
-------------
DataContext="{Binding MainVM, Source={StaticResource locator}}">

- 6,079
- 2
- 9
- 24
-
-
These are some possible, suggested methods. I gave it as a demonstration of some necessary logic. In this case, I meant Copy () - creating a clone for editing. Since editing the original instance will not provide an opportunity to undo the changes made. CopyValuesFrom () - copy values from another instance, namely from the edited clone to the original instance. Produced if Save is clicked after editing – EldHasp Jun 15 '21 at 06:15