MVVM Handling Window Management using Factory Approach - c#

I delegate creation(showing) of my Windows to my WindowFactory, that attaches a ViewModel to the View and shows the window. It is injected into my MainViewModel Constructor parameters.
The factory itself is very simple:
public class ProductionWindowFactory : IWindowFactory
{
public void CreateNewWindow()
{
PhoneWindow window = new PhoneWindow();
{
window.DataContext = new phoneWindowViewModel();
}
window.Show();
}
}
Now, I'm aiming at implementing more functionality of my new windows, that will happen on certain button clicks IN that new window.
As I am fairly new to Factories in general, I'm struggling to grasp a certain concept:
Example:
We have a ViewA that has a ViewModelA attached to it.
That view has a button with a command attached, that tells our WindowFactory to show a new ViewB.
ViewB has a ViewModelB and a close button, that tells it to close ViewB.
Now, since we shouldn't reference our ViewB in our ViewModelB, we have to somehow let it know which view it should close.
I have come up with possible ideas / solutions, but I would really
appreciate you letting me know which one follows the MVVM and Factory
pattern "the most", and which one is usually used in such situations.
Make our ViewModelB take an instance of windowFactory that created ViewB as a parameter on initialization, and build a method in the Factory that closes ViewB and is executed through button click -> command.
Create an IWindowManager? that inherits from IWindowFactory and build a WindowManager class, that extends the capabilities of our WindowFactory, and push it in ViewModel constructors as described above.
Any other correct solution, that I am completely unaware of?
Please bear in mind, that the above is just an example. Ideally, I'd like to implement more of advanced functionality to my windows, and have an ability to create & manage multiple different ones using that one factory.
I have not attached much code, since I'm still at the stage of learning and deciding which solution should I go with.
EDIT - REGARDING POSSIBLE DUPLICATE:
My question differs from the proposed duplicate, as the other one is simply about managing of closing windows - My question is about doing that as well, but following a FactoryPattern.
I have specified very clear guidelines in what I am trying to achieve and in what ways, that are completely different from the question linked.

First of all, the answer is none. The job of a factory is to create new objects, think of it as an elaborate new operator. Also, the idea of following a pattern "the most" is problematic in and of itself. You employ patterns because they help you achieve certain goals, e.g. you employ mvvm to evade coded-ui tests as much as possible, because they are fragile, normally.
That being said, what to do with its view is completely up to the view's view model.
Example: if one view model needs to close its own window, do it with a command as illustrated in the comment. If a view has a close all-button, its view model will have a dependency on some kind of window registry that can enumerate all open windows for the close all-command to close.
When looking at your view model, try to come up with an idea of what services it needs from the rest of the application, and inject those dependencies as interfaces. When implementing the interfaces, most likely there will be classes that implement more than one, e.g. WindowManager might implement IWindowFactory and IWindowRegistry thus making it very easy to put all newly created windows into the list of open windows. The window will have a dependency on the IWindowRegistry, too, most likely, to unregister itself when it gets closed.

The duplicate was not far off. Here is a simple adaptation of the scenario in OP
interface IView {
void Close();
}
class ViewAdapter : IView {
readonly Window view;
public ViewAdapter(Window view){
this.view = view;
}
public void Close() {
view.Close();
}
}
public class ProductionWindowFactory : IWindowFactory {
public void CreateNewWindow() {
var view = new PhoneWindow();
var viewAdapter = new ViewAdapter(view)
var viewModel = new phoneWindowViewModel(viewAdapter);
//Bind
view.DataContext = viewModel;
view.Show();
}
}
If the view model wants to instruct that the view be closed it can ask the injected contract to do so.

Related

Best approach for calling a web service (or similar) with MvvmCross

I've been giving this some thought lately and I was hoping someone who has better knowledge of MvvmCross than myself can shed some light on this. Given the nuances between each mobile platform there are probably a few different factors that can affect this problem. But for this scenario let's assume we want the best approach for a cross platform solution.
So let's say we have a basic View and a ViewModel class setup. Here's an iOS example.
View
public partial class FirstView : MvxViewController<FirstViewModel>
{
public FirstView(IntPtr handle) : base(handle)
{
}
public override void ViewDidLoad()
{
Request = new MvxViewModelInstanceRequest(FirstViewModel.NewInstance());
base.ViewDidLoad();
}
}
View Model
public class FirstViewModel : MvxViewModel
{
public static FirstViewModel NewInstance()
{
return Mvx.IocConstruct<FirstViewModel>();
}
public FirstViewModel()
{
}
}
Now at the loading of this View or at some point just before the view is created we want to fetch some data from the web using a service that we inject using dependency injection; because the displaying of the view depends on that data. Here lies the problem.. at which point from a platform perspective and in the MvvmCross lifecycle would be the most appropriate place to call the web fetch function in the service.
With regards to platform I would assume that we should do it once the view loads. Because if the fetched data is anything other than simple data types it will be inconvenient to work with on Android, as one would have to persist the data to disk and retrieve it after the navigation, due to serialization between activities.
So assuming we called the web fetch during the view loading process. Where is the best place in the MvvmCross architecture to fire it off, that most closely follows the design paradigms. e.g. The View Model. Is there any lifecycle methods that someone could recommend to call it inside as well. Something like the Start method, called after the view model has been created.
First of all, I don't understand why you won't let the platform itself instantiate and do it's ViewModel lifecycle instead of creating a new instance of the ViewModel using Mvx.IocConstruct. That method does not invoke the ViewModel lifecycle and will not call neither Init or Start on the ViewModel.
If you let the platform do this for you, first the Init method will be called with the arguments that you set when using ShowViewModel<T>(args).
When ViewDidLoad invokes the Start method will subsequently be called.
This gives you two places to invoke the Service that you inject in the ctor of the ViewModel.
If you want more control over when to download the data, you could create some ICommand's, which you invoke on your ViewModel in any of the ViewController lifecycle methods. This could be in the ViewWillDisappear/ViewDidDisappear method, or you could fetch the data.
There are so many ways you can do this. In the end it is entirely up to you, and you can't possibly know when a user decides to change to another View. However, you can make qualified guesses and try fetch data before the user actually wants it.
There is a nice article for you to read here, by Rob Gibbens on how you could do Resilient network services. It describes how you could speculatively fetch resources based on what the user is doing, and this way have something ready for the user to see when he enters the View. This could be cached data or fresh data that you are fetching after showing the cached version.
In any case, I would suggest you stop loading your ViewModel's with Mvx.IocConstruct and let MvvmCross handle this for you in order to get lifecycle methods invoked.

Use same viewmodel different windows

My project is build on MVVM. Currently I have a list where i can select an object and add them to another list. What I want to make is a new window where this list is shown (the list with objects that are added) and edit that list in the new window (delte an item from that list).
How should I pass the data (selected object) to another window and be able to update them there?
I currently have it working in one view. In some related questions they advice MVVM light so I tried looking for that, from what I red mvvm light is mostly used to replace the notify property change. Should I use mvvm light or are there some specific patterns I could use?
Both windows will be open at the same time.
If you want to share your ViewModel between windows, you can use a ViewModelLocator. It is not specific to MvvmLight, it just creates one for you with its project template. You can implement it yourself, it is basically a container for your ViewModels. You can look here for the implementation details.
I've got to say that I'm not sure that these are the best approaches and if they are common, it's just what me and my colleagues were using in a WinRT application, so I'll be really glad if someone comes up with something better (both of these are not that clean).
I can think of two ways to pass data (without persisting it)
Pass parameters on page navigation
Have common shared class (Static or singleton class with some common data accessible from all ViewModels)
For passing on navigation:
I have this method in my Navigation service class:
public virtual void NavigateTo(Type sourcePageType, object parameter)
{
((Frame)Window.Current.Content).Navigate(sourcePageType, parameter);
}
and I use it like this in navigation commands:
Navigation.NavigateTo(typeof(PageType), someParameters);
Then you could get the values in the code behind of the navigated page
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var receivedParameter = e.Parameter as TheTypeOfThePassedParameter;
}
And from there to pass them to the ViewModel, maybe there is an option to pass this without code in the code behind but I've not tried this.
Having shared class:
This is pretty much straightforward just have static class or a singleton with the desired fields.

Greedy construction and dependency injection

For a project I am working on, I decided to adopt the MVVM pattern.
My viewmodel needs to launch many different dialogs, which do more than just simply show OK or Cancel buttons. Most dialogs have a listview to select an item from.
To keep the viewmodel "lookless" I am injecting the different dialogs as interfaces in the viewmodel constructor.
public ContractsData(IWindow ProjectSelector, IWindow ContractSelector, IWindow DebtorSelector)
{
//.....
//.....
m_ProjectSelector = ProjectSelector;
m_ContractSelector = ContractSelector;
m_DebtorSelector = DebtorSelector;
}
With IWindow being:
public interface IWindow
{
void Close();
bool? ShowDialog();
void SetOwner(object window);
bool? DialogResult { get; set; }
object DataContext { get; set; }
}
However nice it is to be able to separate data from views from a testing point of view, all possibly needed dialog windows have to be present and fully constructed upon construction of the viewmodel, which goes against one of my principles, that of "lazy initialisation": only construct an object when you need it.
As my viewmodel grows, it will possibly need a whole bunch of dialogs, which will all be created up front and sleeping in memory until needed, which very well may never be.
I was thinking of replacing the actual dialogs with lightweight "Factory" objects, that construct the dialogs on request from the view, but I am looking for a better solution to solve the memory issues with dependency injection.
If you're using a dependency injection container, most of them will be having a feature to inject Lazy<T>. So instead of IWindow you could take dependency on Lazy<IWindow>. Without any special registrations they are clever to inject Lazy<T> for you.
If you're using poor man's injection, you could manually construct Lazy<IWindow> and inject it. Otherwise Abstract factory is another good option.

Calling method of UserControl from ViewModel with Caliburn.Micro

I'm writing a ViewModel-first MVVM application using Caliburn.Micro
My View contains a 3rd party UserControl that implements a Method I want/need to call from the associated ViewModel. How do I do that while still upholding the MVVM principles?
There exists an old thread here on SO where a similar question is asked in a more specific context. I would appreciate it if someone could flesh-out the approaches suggested there a bit.
Approach one suggests that the View could subscribe to an IEventAggregator message. But wouldn't I have to use the code behind file to do that? (I thought that was a big no no in MVVM)
Regarding approach two, I have no idea how to do that. And regarding approach three, thats what I tried first but somehow I didn't quite get it to work.
Let me clarify your understanding:
Yes code in the code-behind is generally avoided, but only because MVVM makes it so easy to bind to viewmodel properties and commands in order to wire up your visual element with the functionality behind the scenes
Code that is view-specific in the code-behind of the view is perfectly acceptable assuming it doesn't cross the boundary of concern. For instance, I have a view in my application that does some visual processing of the page, and to do so I require that there is code in the view. This code may also interact with the viewmodel layer, but it will not directly reference the viewmodel, therefore keeping my components loosely coupled
If you have controls that need particular methods calling, then creating an event aggregator message to propagate the notification to the view is perfectly fine since you are still maintaining the separation of concern between the viewmodel and view (and the application components remain encapsulated and testable)
Example View (I've left all event aggregator wire up code and potential dependency injection stuff out for clarity):
public class MyView : IHandle<SomeNotificationMessageType>
{
// Handler for event aggregator messages of type SomeNotificationMessageType
public void Handle(SomeNotificationMessageType message)
{
// Call a method on one of the page controls
SomePageControl.SomeMethod();
}
}
Obviously, what you wouldn't do is something like this in the ViewModel:
public class MyViewModel : IViewAware
{
public void DoSomethingThatAffectsView()
{
var view = this.GetView() as MyView;
view.SomePageControl.SomeMethod();
}
}
Which violates the MVVM principles since you are tightly coupling MyViewModel and MyView.
What if you wanted to use the Context property in caliburn micro which allows multiple views over the same view model? The code above would break - even if you checked the View type, you would still end up with spaghetti code e.g.
public class MyViewModel : IViewAware
{
public void DoSomethingThatAffectsView()
{
var myview = this.GetView() as MyView;
if(myview != null)
myview.SomePageControl.SomeMethod();
var myotherview = this.GetView() as MyOtherView;
if(myotherview != null)
myotherview.SomePageControl.SomeMethod();
// ad infinitum...
}
}
Of course this is subjective: it may be that your usercontrol affects the viewmodel and the view in a complex way, in which case you might want to consider looking at the architecture and working out how that usercontrol can better fit
Have you got any background on what the UC is and what the method on it does?

Questions regarding appropriate use of ViewModelLocator in MVVM

I am working on a WPF/MVVM app using MVVM Light. Right now my ViewModelLocator is pretty standard; it includes a static constructor that registers the ViewModels via SimpleIoc and has properties returning the current instances of the ViewModels.
I don't know how appropriate this is, but I have been exploring using instances of ViewModelLocator in ViewModels to access properties of other ViewModels and to change ContentControl in one of my views. If there are any major problems with doing that, please let me know so that I can find a way around it. For example, I may have something in a ViewModel like:
private ViewModelLocator _viewModelLocator = new ViewModelLocator();
private void SomeMethod()
{
_viewModelLocator.OtherViewModel.SomeProperty = something;
}
In a different ViewModel I have the following:
private ViewModelLocator _viewModelLocator = new ViewModelLocator();
public ViewModelBase CurrentViewModel { get; set; }
private void SomeMethod()
{
CurrentViewModel = _viewModelLocator.SomeViewModel;
}
In this case, CurrentViewModel is bound to a ContentControl in my view.
At the moment being able to do this is very convenient but I'd like to get some input from more experienced programmers to make sure that I'm not shooting myself in the foot. If there is a problem with it, are there more acceptable routes I can take to achieve the same results?
Now, if there is nothing wrong with the aforementioned approach, I would like to know if it would be appropriate and/or acceptable to make ViewModelLocator static. To try things out, I did a quick changeover to a static ViewModelLocator. In my MainWindow.xaml, I set the DataContext to:
DataContext="{Binding Source={x:Static vm:ViewModelLocator.Main}}"
...and going back to the first example, I can use:
private void SomeMethod()
{
ViewModelLocator.OtherViewModel.SomeProperty = something;
}
and:
public ViewModelBase CurrentViewModel { get; set; }
private void SomeMethod()
{
CurrentViewModel = ViewModelLocator.SomeViewModel;
}
Right now the program works fine using a static ViewModelLocator, but it is in its infancy, so I'd like to know if this is something that could be a viable option in the future or if I should stay away from a static ViewModelLocator altogether.
Any advice or input on these issues would be greatly appreciated. I am still fairly new to programming and I would like to learn techniques that will serve me well in the long run.
If there are no glaring issues with what I'm doing here, please let me know as well.
Thanks.
It is considered incorrect to reference other view models from view models. This breaks the decoupling that is supposed to make you project more testable and maintainable. If I need to have properties accessable from a number of view models I create a service like iUniversalAppDataService and then use the dependency injection built into MVVM-Light to resolve when the vewimodel is created.
ie this is the constructor of your viewmodel:
public New(IUniversalAppDataService AppDataService)
{
_MyAppDataService = AppDataService;
}
That way any changes/properties within that service are available to any viewmodel that implements the service.
the service needs to be declared in the viewmodellocator as well:
SimpleIoc.Default.Register<IUniversalAppDataService , UniversalAppDataService >
I have used this method to create navigation services that respond to user navigation and of course data services from databases or web data services. I strongly suggest using this service approach because it is WAY easier to maintain in the long run should there be changes to your underlying data model or app architecture.

Categories

Resources