WPF and MVVM model and viewModel separation - c#

I am new to WPF and MVVM, and I am a bit confused on how to use model and viewModel for what I need.
The application will have a global "World" object, that will contain a collection of objects of various custom classes that will be created, destroyed and updated continuously by background threads that listen to ports and sockets, being this the body of the application logic. This collection of objects needs to remain static throughout the execution of the application, regardless of page navigation, and be accessible from custom classes and editable from the UI (there will be a page for an overview of the "world" status, as well as pages for detailed views, editing of objects and configurations).
From what I've read, I gather this data should be maintained by the model, and the ViewModel should access it to prepare it for the View. Does this mean that, for every "world" custom class that I create and need to be viewed or edited by the user, there should be a ViewModel to match?
Looking at code samples and tutorials, I see that viewModels objects are linked to views in the XAML code and instantiated when said view page is loaded (and destroyed on exit). How do I link that viewModel object to a specific and existing Model object, from which it should obtain all data and to which the UI input data has to be saved?
To summarize:
World object collection is created in application start (app or
mainWindow scope). For example objects of class Task are created.
Background processes are initiated, that access the tasks collection and do things depending on what they find. (also they can change data, so it has to notify the modelview to display the changes).
GUI navigation is initiated, and controls are created dynamically, that view and edit the data in the world objects. For example, display controls to manage multiple Tasks.
How do I link the Model objects (e.g. a specific task) with the viewModel? On XAML? in the code behind of the viewModel, with some kind unique identifier for each Model instantiation? When adding the controls dinamically in codebehind, passing the model object instance to the viewModel?
What's the best way for the model to notify changes to de viewModel and viceversa?
I would appreciate any guidance or a reference to a code sample that solves a situation like this.
Thanks in advance

Have a service through which each viewmodel can access your model object - see mvvm services

Related

C# WPF multiple windows

probably a beginner question,
I develop in c # wpf a graphical application with different windows, if I now open a new window with button and there, for example, capture a customer, then how can the other window still remain interactible with the open table?
or how can I run a function in another window that is supposed to update a DataGrid of another window (other .xaml file)?
Because neither window should actually control the access or view of the underlying data, they both interact with it via a intermediary class/object.
For WPF this pattern is commonly MVVM: Model, View, ViewModel. Your WPF Windows/Forms are the Views, and the data interaction will be in the ViewModel and Model.
I've not had to learn this in a while, but LearnMVVM looks to be reasonable starting point.
I suggest you Implement a ViewModel (if youre lazy there is MVVM Lite) with public or internal access mods. Then call the specified method to update the ViewModel.
You can pass a reference from your 2nd Window to your MainWindow by passing it though the constructor if you, for some reason, cant use static constructs.
What are you looking for is MVVM-Design Pattern (or MVC):
Model − It simply holds the data and has nothing to do with any of the business logic.
ViewModel − It acts as the link/connection between the Model and View and makes stuff look pretty.
View − It simply holds the formatted data and essentially delegates everything to the Model.
Wikipedia: MVVM
Tutorialpoint: MVVM-tutorial

How to catch PropertyChanged events in multiple Views?

I recently started learning about WPF, which led me to learn about MVVM and eventually MVVM Light, so still a starter in these three. I am building an application with a layout similar to the picture in the link -> Application layout
In order to maintain good code separation and avoid huge files i decided the best approach would be to create a main View, and in that create several smaller Views per "zone" of the UI. From what i read in several tutorials, it is advised to maintain 1 ViewModel per View. Therefore i have a Master View / ViewModel, and several View / ViewModels running simultaneously.
Finally i have a single Model that keeps track of the information I plan to display in the UI. The Model interacts with an external API that can modify the data in it. So besides data being modified by user request (ex: pressing buttons or timers), the data will also change with asynchronous events from the API. Which means I need two way communication between the Model and the ViewModels / Views.
The questions:
1. Do you agree with the "1 view per zone of the UI"? And the 1 ViewModel per View?
2. In the Main View-Code-Behind I instantiate all the ViewModels, and in each View I bind them like in the MVVM Light examples i saw:
<UserControl ... DataContext="{Binding Main, Source={StaticResource Locator}}">
<UserControl ... DataContext="{Binding SideBar, Source={StaticResource Locator}}">
<UserControl ... DataContext="{Binding TopBar, Source={StaticResource Locator}}">
Is this the correct way to instantiate and bind several ViewModels to the respective Views?
3. Each ViewModel is passed a reference to the Main ViewModel (except the Main itself) in its constructor, which is the only one with a reference to the Model. This is how i connect the several ViewModels to the Model. Is this conceptually correct?
4. Initially i was trying to avoid using MVVM Light or other frameworks if i could do all i wanted with the RaisePropertyChanged method. I might be doing something wrong, but for example, when the Model calls RaisePropertyChanged, i can catch that event in the Main ViewModel, however it doesn't propagate to the rest of the ViewModels, so i had to do it myself by calling RaisePropertyChanged a second time:
public MountainTopViewModel()
{
_model = new MachineStatusModel();
_model.PropertyChanged += ModelPropertyChanged;
}
void ModelPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "TestVarModel")
{
// do something else if needed
RaisePropertyChanged("TestVar");
}
}
I'm guessing this is either not the correct way to do it, or there is a better one. So how can I inform all the Views and ViewModels when a property changes in the Model, without having to re-call the method in different places?
Sorry for the long story, i would appreciate some help.
This seems unwise to me:
The Model interacts with an external API that can modify the data in it. So besides data being modified by user request (ex: pressing buttons or timers), the data will also change with asynchronous events from the API. Which means I need two way communication between the Model and the ViewModels / Views.
I would have the async API events driving changes in the viewmodel, not the model. Then, in response to changes from the async API or from the View, the viewmodel does its usual thing: Updates the model and raises events which the view responds to. The viewmodel already plays that role, so use what you've got. Your scheme adds complexity that you don't need, and it's more complexity than you may realize. Item # 4 in your question is just the tip of the iceberg of that added complexity; believe me, it'll only get uglier from there. Don't do that to yourself. You're young. You've got everything to live for.
It's not unusual for a viewmodel to handle the PropertyChanged event of another viewmodel, or for a viewmodel to expose specific custom events which fire when specific properties change value. It might have a NameChanged event or whatever. But I don't see any particular need for that in your question, as I understand it.
1. Yes.
2. If MVVMLight does things the way you've got it there, do that. Plunkett's Razor: Whenever possible, conform to the practices of the framework you're using. Consistency is golden in programming for many reasons, and if you follow the "rules", you'll usually find the framework will be there waiting to help you instead of fighting you every step of the way. This isn't a law of nature, but it's an amazingly reliable rule of thumb.
3. That's conceptually a little shaky. Ideally, we try to write viewmodels that aren't dependent on "parent" viewmodels. Your Library viewmodel has to know what a Book viewmodel is because it contains a collection of them, but a Book viewmodel can often be more useful if it doesn't depend on a Library. Imagine writing a Wheel that's got all kinds of dependencies on Car, and then having to implement Bicycle. Do you give Bicycle an Alternator, or do you create a dummy Car? Times like that you start to daydream about moving to a commune in Vermont and making useful objects out of wood.
I would probably have a model type for each viewmodel, and give all the viewmodels a reference to their own model in their constructors. The models would probably have the same parent-child relationship as the viewmodels. If your model is Entity Framework or something instead of "POCO" classes, then yeah, one model for everybody or whatever. But still, just hand it to them directly.

MVVM: custom class for grid objects that is only accessible by code behind

I'm writing a C# UI and trying to follow the MVVM pattern. My design consists of a grid representing a join of two objects in the database, some text fields, and some buttons.
I've been successful binding the data context of the xaml to my view model code, and my code-behind (.xaml.cs) is very minimal. I've done this by adding a class called GridObjs to hold the grid objects (i.e. objects with properties specific to the UI that aren't members of the model layer objects). Unfortunately, however, this approach requires that I expose my GridObjs class publicly in order for it to be used by the .xaml.cs.
Is there a solution that allows me to hide GridObjs but also allows it to be accessible by the .xaml.cs?

MVVM ViewModel-Model

Can I create an instance of the ViewModel in the View or it's inappropriate? I would need it, because the Command of a MenuFlyoutItem dynamically changes depending on the content of the Button (the Button content depends on a Json file).
Usually there are two approaches for ViewModel lifetime - singleton and tied to a specific instance of the view. For global ViewModels that are tied to a certain View for the whole lifetime of the app you will create a singleton instance of the ViewModel. Example for this could be the ViewModel of the root page of the app. This page will definitely appear only once in the navigation stack so you can safely use just one instance. A problem appears when there is a way for the user to repeat one View multiple times in the navigation stack. If you were using just one singleton instance of the ViewModel, by navigating to the second instance of the View you would essentially lose the the data tied to the previous instance and after navigating back you would see different data. Example would be a shopping app, where you have a product (A) and in the product view you have a list of related items. If the user selected one of them (say product B), then in cas of singleton ViewModel the instance would be refreshed to contain data of product B and when going back you would have to manually change the data back to product A. By having multiple instances of one ViewModel for each instance of the tied View in the navigation stack you can avoid reloading the data, which could be costly in case they are acquired from a remote service, for example. You can always manage all active ViewModels in a global array and remove the references to the ones no longer needed, so they can be freed up from memory.

How to instantiate View from ViewModel?

Events occur in our Model and ViewModel that necessitate creating the appropriate View. The question is how to do this and avoid having any View code in the VM or M?
Here's the sequence of events so you can see this dilemma:
The user sets a number fields in a form to start a long running background process and then clicks the "Start" button. If this long running process succeeds then it needs to popup a chart with graphs to show the results. However, if the data fails processing for any reason then it can't popup charts, instead it logs an error message which is show in the a text box on the form.
Right now, that start button calls a method in the ViewModel which actually starts the background thread.
Only the background can determine when or if to create the view.
Currently we have this working by using an interface called ChartInterface. The view implements this interface and then sets a callback delegate all the way down to the backend model. When it decides to create the Chart it invokes the callback and uses the interface to pass the appropriate data and such.
However, this presents a problem because it can potentially produce dozens or hundreds of charts. So we need to have a "Dashboard" with a list of all the charts for the user to select which one to see.
So now the backend needs to decide when or if to create the Dashboard View, then add Chart View to it.
So it's getting messier because there will be increasingly more of these situations as we have lots of Models that need views so creating tons of callback delegates gets ugly fast.
An idea that seems to simplify instead of lots of callbacks will be to only pass an interface to a ViewBinder to the backend. Then each time it creates a model object, it can pass it to the ViewBinder to see if it wants to bind any view object to it.
Our thinking is that most any of the backend objects will be interesting (eventually) to monitor graphically. So if everyone of them after contructing is passed to the ViewBinder interface, then the view can decide if it wants to bind anything to it.
This is sounding better all the time.
The answer became clear while working on the code.
public interface ModelBinderInterface {
void TryBind( object model);
}
instead of one global "server locator" it's more natural for EVERY view object to implement this interface.
Then when it creates any ViewModel objects it assigns itself to the ModelBinder property of the the viewModel object.
Now the ViewModel can pass this same interface to the back end process.
When ever any relevant model gets instantiated, then it calls the ModelBinder with the object.
Then the View object can decide if it can instantiate the object, if not, it can pass the call up to it's parent which also implements ModelBinderInterface.
This way each view can handle instantiating views that it understand whether that be adding a control to a DataGridView or binding the object to a ListView, etc.
Of course, this still allows for a singleton ModelBinder because the lower levels can keep handing the call up to the top level application ModelBinder which there's only one and it can offer singleton instances.

Categories

Resources