Getting around circular dependency - c#

Could I get help with a little issue I am encountering regarding splitting projects into different tiers. In my ViewModel logic I have code where I create a new instance of a window when a button is clicked (I use ICommand interface for that)
The problem is however, that this requires my View folder which is in the presentation layer, I can’t reach it as my presentation layer is dependent on my ViewModel in the logic layer.
I would just move the code that deals with the creation of the pages to the view code behind but I also pass the current instance of a viewmodel as a parameter for that new window being created (for eventhandling purposes).
Any help is much appreciated! Thanks.

A view model shouldn't create instances of windows. What you could do is to inject your view model with a service that is responsible for creating windows, e.g.:
public class MainWindowViewModel
{
private readonly IWindowService _windowService;
public MainWindowViewModel(IWindowService windowService)
{
_windowService = windowService;
CreateWindowCommand = new DelegateCommand(() =>
{
_windowService.CreateWindow(new SomeViewModel());
});
}
public ICommand CreateWindowCommand { get; }
}
Define the IWindowService interface in the view model project and the concrete implementation of it in the view/presentation project:
public class WindowService : IWindowService
{
public void CreateWindow(SomeViewModel vm)
{
Window win = new Window();
win.DataContext = vm;
win.Show();
}
}

Related

Using MvvmLight.Messaging.Messenger to instantiate new View + ViewModel (Window)

I have my MainView and an associated MainViewViewModel which are linked by ViewModelLocator.
Within MainViewViewModel there is a command which should trigger a new Window to open which has it's own View and ViewModel (NewView and NewViewViewModel).
In a lot of the examples I've seen it is suggested to use Mvvmlight's Messenger to do something like this:
public class MainViewViewModel
{
private void OpenNewWindow()
{
Messenger.Default.Send(new NotificationMessage("NewView"));
}
}
And then register the NewViewViewModel and handle the message like this:
public class NewViewViewModel
{
public NewViewViewModel()
{
Messenger.Default.Register<NotificationMessage>(this, NotificationMessageReceived);
}
private void NotificationMessageReceived(NotificationMessage obj)
{
if (obj.Notification == "NewView")
{
NewView view = new NewView();
view.Show();
}
}
}
However, this doesn't work because the NewViewViewModel isn't yet instantiated (so isn't registered with Messenger). Additionally, this doesn't fit with MVVM because NewViewViewModel is responsible for creating NewView.
What is the correct way to achieve a simple command which instantiates and opens a new View and ViewModel pair which are linked via ViewModelLocator and setting of DataContext="{Binding NewView, Source={StaticResource Locator}}" in NewView.xml?
Use a window service:
MVVM show new window from VM when seperated projects
You may either inject the view model to with an IWindowService implementation or use a static WindowService class:
public static class WindowService
{
public static void OpenWindow()
{
NewView view = new NewView();
view.Show();
}
}
Dependency injection is obviously preferable for being able to unit test the view model(s) and switch implementations of IWindowService at runtime.

WPF MVVM compliant way to open views

I would love to find a simple and MVVM compliant way,
to open a new view from the MainWindow.
I have already worked through some instructions and tutorials.
But somehow none really worked or it was a mixture of code behind.
I would like to open a view after pressing a button and edit an ObservableCollection in it.
I have already created DataTemplates in App.xaml and mapped the ViewModels with the respective views.
But I don't know how to cleanly open a separate window from the MainWindow (MainViewModel) via an ICommand for another ViewModel.
You should't open a window directly from the MainWindow nor the MainWindowViewModel. But the view model may use a service to open a window:
public class MainWindowViewModel
{
private readonly IWindowService _service;
public MainWindowViewModel (IWindowService service)
{
_service = service;
}
//...
public void OpenWindowExecuted()
{
_service.ShowWindow();
}
}
Service:
public interface IWindowService
{
void ShowWindow();
}
public class WindowService : IWindowService
{
public void ShowWindow();
{
Window window = new Window()
window.Show();
}
}
You could easily mock out the service in your unit tests.

MVVM light, send message via Messenger from ViewModel to new child window, which is not initialized yet

I've following architecture:
desktop application, .Net 4.5, C#, WPF, MVVM Light, Messenger, IoC - ViewModel locator, so ViewModels doen't know anyhing about Views.
I have main view with data grid of some elements, and I want to display details of each individual element in new/child windows after double click on data grid.
I've bind event double click on main view to main view model. From this event handler in main view model, message is sent via Messanger.
New view (new/child window) is created in main view via delegate of also double click.
New/child window is a view which locate his view model and this view model register to the specific message in his constructor.
The problem is that new/child window (new view, and view model so on) is created too late, because message is already sent when new view model register for it.
Do you know maybe some patterns for such architecture. Any ideas will be appreciated.
It would help to know exactly what you try to do.
If your problem is just to display a detailed Window when double click on a row, I would say: create only one childWindow at start, and play with its visbility when required.
If you really need a new window each time, you could create it from your viewModel with an injected service for example.
In any case, you never has to create your window from main view! Either you create one window at start, either you dynamically create it from view model.
You cannot hope to create it from view and send the message in your view model.
Edit about the injected service, you could use something like that:
public interface IWindowService
{
void Open<TWindow>(ViewModelBase viewModel)
where TWindow : Window;
}
public class WindowService : IWindowService
{
private readonly IUIDispatcher _dispatcher;
public WindowService(IUIDispatcher dispatcher)
{
_dispatcher = dispatcher;
}
public void Open<TWindow>(ViewModelBase viewModel)
where TWindow : Window
{
_dispatcher.Run(() => OpenThreadSafe<TWindow>(viewModel));
}
private static void OpenThreadSafe<TWindow>(ViewModelBase viewModel) where TWindow : Window
{
var view = (TWindow) Activator.CreateInstance(typeof(TWindow), viewModel);
view.Show();
}
}
public class UIDispatcher : IUIDispatcher
{
public void Run(Action action)
{
var dispatcher = DispatcherHelper.UIDispatcher;
if (dispatcher == null)
{
action();
return;
}
DispatcherHelper.CheckBeginInvokeOnUI(action);
}
Note this DispatcherHelper come from MVVMlight, but you could erplace it easily.
Hope it helps.
The problem is that the ViewModel Locator creates the viewmodel instance only when it is needed (lazy loading).
just configure the ViewModelLocator to instantiate the viewmodel eager instead of lazy. This is done by passing the parameter "true" to the IoC Container.
Sample:
namespace Administration.ViewModel
{
public class ViewModelLocator
{
public ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
//Eager Loading
SimpleIoc.Default.Register<UserManagementViewModel>(true);
//Lazy Loading
SimpleIoc.Default.Register<InformationManagementViewModel>();
}
public UserManagementViewModel UserManagementViewModel
{
get
{
return ServiceLocator.Current.GetInstance<UserManagementViewModel>();
}
}
public InformationManagementViewModel InformationManagementViewModel
{
get
{
return ServiceLocator.Current.GetInstance<InformationManagementViewModel>();
}
}
public static void Cleanup()
{
SimpleIoc.Default.Unregister<UserManagementViewModel>();
SimpleIoc.Default.Unregister<InformationManagementViewModel>();
}
}
}

MVP view/presenter registration

I'm working on an MVP based GUI architecture for a WinForms application and would like to use Autofac to keep track of the different parts. I keep running into circular component dependencies and would appreciate a gentle push in the right direction.
The architecture is based on this post where the View is as passive as i gets. The View holds no reference to the Presenter. The View is passed to the Presenter on construction. So in the non-DI world you would start your program with:
var MainView = new MainView();
var mainPresenter = new MainPresenter(mainView, new DataRepository());
Application.Run(mainView);
Ok, so the Presenter needs to know about the View instance to do its job. How can I express that in the registration code? This is what I've tried:
builder.RegisterType<MainPresenter>().PropertiesAutowired().SingleInstance();
builder.RegisterType<MainView>().As<IMainView>().PropertiesAutowired().SingleInstance();
And then in Program.cs:
var mainPresenter = Container.Resolve<MainPresenter>();
Application.Run(Container.Resolve<IMainView>() as MainView);
But this way I need to remember to create the Presenter instance. However I would like to express in the registration that if I request a IMainView instance the MainPresenter should be kicked into action. But how....
Any hints, mockery or derisive laughter are welcome
I think you should be able to solve it this way: Register the presenter and view without property injection since you say the view needs no reference to the presenter, and constructor injection is considered best practice in Autofac:
builder.RegisterType<MainPresenter>().SingleInstance();
builder.RegisterType<MainView>().As<IMainView>();
Inject the view into the presenter through constructor and publish it as a readonly property:
public class MainPresenter
{
// Private variables
private readonly IMainView _view;
// Constructor
public MainPresenter(IMainView view)
{
_view = view;
}
// Properties
public IMainView View
{
get { return _view; }
}
}
Then you fire up the application through a single resolve:
var mainPresenter = Container.Resolve<MainPresenter>();
Application.Run(mainPresenter.View as Form);
Finally, if you find later on that you need a reference from the view to the presenter, I think you would have to use property-injection on the view to avoid circular reference exceptions. Then you can register the view like this:
builder.RegisterType<MainView>().As<IMainView>().PropertiesAutowired(PropertyWiringFlags.AllowCircularDependencies);
and supply the view with a read/write property that will be set by Autofac
public MainPresenter Presenter { get; set; }

windows form & design pattern

i am familier with mvc,mvp or mvvm patter. so i was searching google for implementing good design patter for win form apps. i found lots of article.few guys said mvc is good and few guys said mvp is perfect for win apps. i found a very small code which implement mvp in win apps. i go through the code and found that developer has to write lot of extra code to bind treeview or any control.
the code as follows
public interface IYourView
{
void BindTree(Model model);
}
public class YourView : System.Windows.Forms, IYourView
{
private Presenter presenter;
public YourView()
{
presenter = new YourPresenter(this);
}
public override OnLoad()
{
presenter.OnLoad();
}
public void BindTree(Model model)
{
// Binding logic goes here....
}
}
public class YourPresenter
{
private IYourView view;
public YourPresenter(IYourView view)
{
this.view = view;
}
public void OnLoad()
{
// Get data from service.... or whatever soruce
Model model = service.GetData(...);
view.BindTree(model);
}
}
please someone go through the code and help me to understand the flow because how code should be written in mvp patter that i dont know. thanks.
This code is already using the MVP pattern.
It declares an interface IYourView and a concrete class YourView that implements System.Windows.Form and this new interface. Essentially what that is doing is creating a new form with the added requirement that it also implements the BindTree() method defined in IYourView.
The YourView class (form) then has a dependency of YourPresenter in order to hook up the OnLoad event with the presenter, although I'd do it where the presenter subscribes to the form's OnLoad event instead.
The presenter YourPresenter takes as a dependency an instance of YourView and it can then use that instance in the rest of its logic.
Now, to use that you would follow a process similar to this:
Create a new instance of YourView (which then in turn creates the presenter)
Implement logic in the presenter (ie- create GetModel()) to create the Model that you want to bind to the tree
Call view.BindTree(model) in the presenter where model is what you just created in the previous step
So, create an instance of your view:
IYourView newView = new YourView();
Then in your presenter class:
Model model = GetModel();
newView.BindTree(model);

Categories

Resources