How to catch PropertyChanged events in multiple Views? - c#

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.

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

What is the difference between .xaml.cs and ViewModels/ViewModel.cs?

I have been following this tutorial on MVVM pattern using caliburn micro
https://www.youtube.com/watch?v=laPFq3Fhs8k
What is the difference between .xaml.cs and ViewModels/ViewModel.cs ?
I see we put our code for the shellview in ShellViewModel.cs, but when I, for example, choose an event handler for a Button, visual studio takes me to .xaml.cs and not to the ViewModels/ViewModel.
Do I have to stick to one or each file has a different role/responsibility? ( considering that I want my code to still be following MVVM pattern )
Files ending in .xaml.cs are what is called the View's "code-behind". Anything inside this file is tightly coupled with the View.
If you want to follow the MVVM pattern, you will code almost all of the interaction of the UI with your Models (example: click of a button change some data or get some data from the database) on the ViewModels (.cs files), which are independent from the Views.
The only link between the View and the ViewModel is that the ViewModel is the DataContext of the View. In other words, the View knows about the ViewModel, but that ViewModel does not know anything about the View.
Event Handlers are not generally used in a MVVM world. You need to use Commands. But that is a whole other question/answer.
The important thing to keep in mind is that MVVM comes to address, mainly, two things: the Separation of Concerns (UI vs UI Logic) and Testability of your software.
I'll start by suggesting that you learn the basics of the UI framework you're using (WPF, etc.) before adding an additional framework on top of it. I've seen that this only makes the learning curve steeper.
With that said, the .xaml.cs file is what is commonly referred to as the code behind. This is the code that "controls", so to speak, the UI. You'll note, for example, that these are all "partial" classes because there's going to be some auto-generated code when you compile that does view-specific things like bindings, etc.. The xaml.cs file should be used sparingly and only when you need to know or operate on specifics of the View itself.
With MVVM, you'll often see code behind classes that are almost completely empty, with just a constructor present. The logic in these cases is moved to a "View Model" class which provides a link between the View and the Model (take a look at this SO post for a more thorough description). You should bind to objects in the View Model, and use it as the data context for your view. It contains all the logic to define how the view effects your model.
So - applying this to event handlers... An event must live in the code-behind, because you can't explicitly bind to one in your VM. You could easily call the function you want by accessing the ViewModel right inside that event handler, and there's nothing particularly egregious about this approach. That said, there is another concept called a Command that will live in the View Model itself; a command, as opposed to an event handler, is a Property, so you can bind to that in your .xaml file using
...Command="{Binding FunctionNameHere}"...
It also has nice features like being able to define when the command is valid (so you can disable your button automatically when, for example, the form is missing a required field).

MVVM without commands

I'm learning Silverlight/MVVM. Now I'm facing problem with Commands, that I think are just overcomplicated. I wanted to execute close on child window after command.
According to separation of concers it should be execute from view, as I understand.
As far as I looked for solution I found it and it wasn't trivial for such a trivial task.
To sum it up, I must say that separation of view, viewmodel and model are great ideas.
Also Binding from View to ViewModel is nice and clean.
But what about Commands. As I understand they are just piece of code to execute (like delegates).But they are too complicated and troublesome.
I want to know you opinion. What about idea that VieModel would have properties and normal public methods, that it will be executed from events of views. If I will not pass any view related element to the view model it still will be MVVM, right?
Of course, there will be one drawback, that i will have to bind separatly IsEnabled to properties in ViewModel to mimic CanUpdate functionality of Commands. It's not that you view doesn't know about ViewModel.
Views are not very testable, are they?
It would be very flexible. For example, in event for click i would do some strict view logic, call method from viewmodel object and then maybe call another method and after all that do some more view logic.
So, what do you think?
You can try using Cailburn.Micro. It is an open-source framework that runs over WPF and hides some of it complexities. For example, it replaces command-classes with just plain method calls.
You can implement windows-closing by returning a special result that will do the actual closing of the view. That way your ViewModel will still be fully unit-testable, as you can check that expected result is returned, and it will not be view-aware.
Here is an example on how to implement this: https://stackoverflow.com/a/10175228/258737

When is it ok to combine 2 viewmodels into 1 instead of using some form of viewmodel-viewmodel communication?

I have 2 viewmodels that each have their own view.
the first view model has 3 properties being displayed by the view:
PolicyProvider
PolicyType
PolicyNumber
the second view model has only 1 property being displayed by its view:
TypeOfInvestmentFund
There is a 1 to many relationship between the PolicyType and the TypeOfInvestmentFund.
Both of these view models and their views are being displayed as user controls inside a parent form.
The available choices for the TypeOfInvestmentFund is dependent on which PolicyType is selected in the other view.
To me this feels like these 2 view models could be combined, because
a) they are clearly somewhat coupled
b) the controls are both so small and simple that joining them will not create a complex and unmanageable object.
However this data is fairly unrelated; unrelated enough that the user would still want the data visible in seperate parts of the form (and therefore be placed on seperate views).
I personally feel that combining these 2 view models and having 2 seperate views connect to it to display different parts of it is a lot less overhead then managing the communication between the 2 objects.
I could however create loosely coupled events with the Prism Event Aggregator, and although I have never done this it is probably not much to manage, and keeping these 2 view models seperate would preserve seperation of concerns. Furthermore if other controls were to appear later on in development that also need this information, I cant keep absorbing them, so starting an event aggregator at this stage would prevent rework as the events would be available already to subscribe to. It is still more work then just combining the view models.
Which one of these 2 is 'more correct'? I understand its a judgement call, but I can't decide so I'm looking for opinions to help me make up my mind.
A ViewModel reflects the View, not the Data
If your View shows a Policy and a dynamic TypeOfInvestmentFund, then by all means your ViewModel should have both those objects.
Personally I would have my ViewModel expose a Policy model to the View, and have the PolicyModel contain properties for Provider, Type, Number, and InvestmentFund
I could then use DataTemplates to tell WPF how to draw each object. Here's a rough example outlining how you would do that:
<DataTemplate DataType="{x:Type local:PolicyModel}">
<StackPanel>
<local:PolicyView />
<ContentControl Content="{Binding InvestmentFund}" />
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type local:InvestmentFundA}">
<local:InvestmentFundA />
</DataTemplate>
<DataTemplate DataType="{x:Type local:InvestmentFundB}">
<local:InvestmentFundB />
</DataTemplate>
Edit
If Policy and TypeOfInvestment are two separate objects, I'd keep their Models separate, and put them both in the same ViewModel. Models are for modeling your data, while ViewModels are for modeling your View
I look at problems like this as being very similar to database normalization. On the one hand, normalization is good practice, as is creating two separate view models. But at the same time a certain amount of denormalization has been known to help performance as well.
I personally feel that combining these 2 view models and having 2 seperate views connect to it to display different parts of it is a lot less overhead then managing the communication between the 2 objects.
And that statement says it all. While combining the two view models might not be considered "best practice", the feeling I'm getting from you is that it makes sense for your application (based-on the levels of coupling and complexity that you mentioned). I would say go ahead and combine them and keep an eye on how it performs.
Ok thank you for the replies. Got a bunch of ideas from Rachels suggestion (upvote for you ma'am) but none of them paned out. In the end the project manager didn't like the idea and wants me to implement a more standard approach for readability and to prevent rework, so I'm going to go the message root.
Instead of eventaggregator I'm just going to make the parent subscribe to the PropertyChanged event of the Policy child and then change a property of the TypeOfInvestment child.
I'm kinda bummed I didnt get to implement the viewmodel merge as it really made more sense to me.

Winforms MVP Grid Events Problem

I am trying to implement the MVP pattern for WINFORMS. Its a simple for with a button and a Grid, on button click, the grid will load, and user can fill in values into the grid.
For my button click event, I have something like this:
_presenter.LoadGrid();
Which is simple and straightforward.
My question is, in regards to grid...
I am planning to have a row click event firing....for enabling/disabling the subsequent input fields for the specific columns/rows of the grid etc.
I understand that the presenter should not contain any GUI elements and the View(form) shouldn't really contain Logic?
So, to have that GridRowClick event firing, I need to manipulate the grid (GUI) based on business rules (Logic). I am lost between letting the presenter handle the logic of that click event or the form?
If the presenter is to handle the click event, wont that include the gui components?
If the view is to handle the click event, the fieldnames etc are all business driven(logic), dynamically binded based on datatable returned from the business layer.
Any advice will be much appreciated.
Cheers
There are (at least) two variants of MVP.
Passive View Pattern
Supervising Controller Pattern
Passive View, as its name suggests, treats the UI as a more or less passive interface between the user and the application. It moves as much testable code to the presenter as possible leaving the view to handle only the most basic UI updates.
Supervising controller gives the view a little more responsibility by letting it handle data synchronization. This is usually done through data binding.
In either case event handling is accomplished by delegating to a presenter method:
EventHandler()
{
presenter.HandleEvent();
}
If handling the event requires making changes to the form, you expose what needs to be updated as a property:
public string PropertyThatNeedsToBeUpdated
{
get
{
return Control.Property;
}
set
{
Control.Property = value;
}
}
For Passive View, grids are a hurdle. Their complexity make it cumbersome to capture all the possible events. With Supervising controller, grids are much easier since you leave data synchronization up to the data bound controls.
You have to make the judgment call as to which is more appropriate for your situation.
The key is getting all that business logic into the presenter where it's testable.
The view should call the presenter to perform the business logic, passing the information needed (e.g. the data associated with the clicked row).
The presenter then performs the business logic and updates the data.
Depending on what type of changes you need to make, that might be all you need to do, since the existing data binding might be sufficient to update the view automatically. If it isn't sufficient, the presenter can make one or more calls to the view (via its interface of course) in order to make the required changes.
As you say, you should aim to minimize the amount of non-trivial code in your view, and in particular, the view shouldn't have any business logic in it.
EDIT:
Some good general information on MVP and other presentation patterns here: http://martinfowler.com/eaaDev/uiArchs.html
You might want to check out Part 4 of the video series from Polymorphic Podcast. He uses the supervising controller pattern and shows a technique for handling data grids. The whole series was actually a good introduction for me.
http://polymorphicpodcast.com/shows/mv-patterns/

Categories

Resources