I've recently needed to synchronize values from a higher up view model (bound to a custom tab content control) to the base one (bound to the host view) for the CanExecute delegate in the host view to use. The base model has the instance of the top one, among others.
The only thing that I can think of for it to know when a value changes higher up is to subscribe to the PropertyChanged event. But, that seems excessive considering how many times that event would get fired for all of the other properties. It also doesn't feel right for MVVM (but I may be wrong).
Right now, I'm setting it all in a central method in the manager class where the magic happens to make sure the values match up:
If setDealable Then multilegViewModel.IsDealable = isDealable
multilegViewModel.IsIndicative = (Not isDealable)
' [...]
tktViewModel.IsCommandOtherEnabled = (Not isDealable)
tktViewModel.IsCommandBuyEnabled = multilegViewModel.IsBuyButtonEnabled
tktViewModel.IsCommandSellEnabled = multilegViewModel.IsSellButtonEnabled
tktViewModel.IsDealable = isDealable
tktViewModel.IsIndicative = (Not isDealable)
' [...]
But, smaller sets of the "multilegViewModel" properties are being set elsewhere, so I have to find them all and add the copy over. The risk is having another developer leave out such a pairing somewhere.
So, does anyone have ideas other than one view model subscribing to the other to ensure that the values always get set?
Note: The dual language tags are on purpose. It's a mixed language solution, such as the manager being VB.NET, but the models are C#, so I accept suggestions in either one.
UPDATE: I've changed my approach and greatly simplified it, so my initial reason for needing this is no longer valid. But, I may have an edge case or two that could still benefit from this.
Related
I have a property called PriceChangeInPercentWeekly which has other properties like LastOpenPrice, LastClosePrice, etc.
I am changing these continuously. But how can I raise PropertyChangedEventHandler for PriceChangeInPercentWeekly when a sub-property is changed?
When PriceChangeInPercentWeekly itself is changed, I raised it using my custom SetField function. But how can I do this for sub-properties. Because sub-properties do not know the instanced class, right?
PriceChange priceChangeInPercentWeekly;
public PriceChange PriceChangeInPercentWeekly
{
get => this.priceChangeInPercentWeekly;
set => SetField ( ref this.priceChangeInPercentWeekly, value,
"PriceChangeInPercentWeekly"
);
}
Based on the comments, it sounds like you have a issue with properly binding in a collection case. When dealing with collections in MVVM, there are actually 3 seperate kinds of bindings/Change Notifications you need. If any one is missing, you end up getting issues with non-updates pretty quickly:
Whatever class is holding LastOpenPrice, LastClosePrice, PriceChange and the like - it needs change notificaiton on each and every property. Whatever template you use to display that class, needs to properly bind to each of those properties.
You need change notificaiton if anything is added or removed from the Collection. That is the only change notification ObservableCollection<ClassThatHoldsThosePrices> takes care off.
Whatever property exposes the ObservableList<ClassThatHoldsThosePrices> or its Collection View needs change notificaiton as well. ObservableCollections do not support bulk additions. With a big changes you usually have to build a new list in the background, then replace the whole collection.
At this point it usually becomes a question of properly setting up (or automatically having set up) the 3 kinds of bindings. The proper MVVM pattern is not a easy thing to learn and it can not tell if you did it properly, so it is hard to say where the issues could be. About 8 years ago I wrote a short introducing which I think should still be okay-ish for learning the basics: https://social.msdn.microsoft.com/Forums/vstudio/en-US/b1a8bf14-4acd-4d77-9df8-bdb95b02dbe2/lets-talk-about-mvvm?forum=wpf
Is it possible to just "link" two properties of different ViewModels in a way such that when one property changes, the other one changes too. So in essence, I want two properties in different ViewModels behave as if they were one.
It would be nice if I could just do something like the following in my ViewModels:
WhenPropertyChanges(() => SettingX).CopyValueTo(() => ModelView2.SettingX);
Example: On my settings page, when I change a setting, I want the new value to be available in the ViewModel of another page.
I know I can achieve that with the third Layer (Model), but it feels a bit clunky and the way I solved it for now doesn't feel right (Firing events).
I've implemented following MVVM-Pattern from this page: http://www.wintellect.com/devcenter/krome/linking-property-change-notifications-in-xamarin-forms-or-wpfsilverlight. As far as I understood, the author says his code makes it possible, but unfortunately he doesn't show how.
I also found this article (http://blog.alectucker.com/post/2014/07/26/using-messageingcenter-in-xamarin-forms-for-viewmodel-to-viewmodel-navigation.aspx), but I don't necessarily want to navigate to the other View. Still, maybe I can use this MessagingCenter somehow to achieve my goal?
This is addressed in the final paragraph of my article that you reference. I use a simple extension method to do it. An example of this can be seen in the source code example from the article, in this file: https://github.com/Wintellect/XamarinSamples/blob/master/PropertyDependencyDemo%2FPropertyDependencyDemo%2FMvvm%2FObservableExtensions.cs
For your specific example, it would look something like this:
// using PropertyDependencyDemo.Mvvm;
// ... use the namespace above that contains the ObservableExtensions class
ModelView1
.WhenPropertyChanges((a) => a.SettingX)
.AlsoInvokeAction(() => ModelView2.SettingX = ModelView1.SettingX);
All this does is hook into the PropertyChanged event of the source viewmodel for you in a name-safe way.
One word of caution though: you need to be careful to not create a situation where you inadvertently prevent an object from being garbage collected. The reason this can happen is that in this example, ViewModel1 will now have a PropertyChanged handler that references a PropertyDependency object that in turn references both ModelView1 and ModelView2 due to the captured references in the Action lambda expression.
IF you know for sure that this won't be a problem (perhaps both go out of scope together), then there is nothing to worry about. But if you find yourself facing a situation where you need to prevent ModelView1 from keeping ModelView2 pinned, then you can do so using a WeakReference. Again, this is unlikely to be a concern, but if you find it leaking memory then you can change the above to this:
// assuming "TModelView" is the class name of the viewmodels
var wr = new WeakReference<TModelView>(ModelView2);
ModelView1
.WhenPropertyChanges((a) => a.SettingX)
.AlsoInvokeAction(() => {
TModelView mv;
if (wr.TryGetTarget(out mv))
mv.SettingX = ModelView1.SettingX;
});
I think if the navigation is lineare ( you only need the information of page 1 in page 2 ) you can use the MessagingCenter to do what you want.
If the user is able to change the data in the page 2 ( and be updated in the page 1 ) the messagingCenter is a little to tricky to use. I think you can use the first link you provide. Just use an abstract class with all shared data in your ViewModels.
If you want more help put an more completed code example.
I'm currently writing a rather small desktop application using the MVVM Approach. It also utilizes Entity Framework 6 for the database access. Right now, my top-level ViewModel instantiates the 'smaller' ones, and passes them the DbContext I'm using. The smaller ViewModels I use correspond to UserControls sitting in a separate TabItem each. But if I change something in the database in one tab and switch the tab afterwards, the UI isn't keeping up, logically, since there is no OnPropertyChanged("SomeObservableCollection") Happening.
I thought about just "refreshing everything inside" when a TabItem becomes active, but on one hand, I don't know how to do this (it would basically be doing OnPropertyChanged(..) for every UI-relevant property, right?), and on the other hand, it does seem neither elegant nor 'correct'.
What should I do about this? And is using one global DbContext even good practice? I read about short-lived DbContext instances being better, but I also found the opposite statement regarding desktop applications...
How do you handle this scenario? It can't be that rare actually, can it? Thanks!
You have to look at using a Messenger (MvvMLight) or EventAggregator (Caliburn.Micro).
So when your context has changed you pass the message about it and update your SomeObservableCollection so OnPropertyChanged("SomeObservableCollection") will be raised.
Might Help . I have done this in small project . any better solutions are welcomed.
**Viewmodel 1 Where changes occurs**
//database call
string result = _dataService.Insert(data);
if(result=="Success")
{
//notify viewmodels using default messenger instance
MessengerInstance.Send(new NotificationMessage("notifycollection"));
}
Viewmodel 2 where we receive notification
public AssignTimeSlotViewModel(IDataService dataService)
{
// registering the notification
MessengerInstance.Register<NotificationMessage>(this, receiveNotification);
}
#region Messenger - receivers
private void receiveNotification(NotificationMessage msg)
{
if (msg.Notification == "notifycollection")
{
/// Call Database to keep collection updated.
// raise propety changed event if neccessary.
// Do Something
}
}
#endregion
Thats not an easy subject at all.
If you handle with a small amount of data and performance is not a problem for you, you could update your bindings every time the view gets loaded. Here you can see how to accomplish that.
A Problem if you do that is, that you have to do some extra logic for saving last selected items and reselect them after the view gets loaded.
Using a messenger could be an option too. But in my experience the messenger could make thinks messy if it is not implemented correctly. For example please dont use some magic strings as messeages.
This is more of an architecture / design question.
I have run into a few projects in the past written in WPF/Windows Forms, etc. that have complex screens with a lot of fields and these fields are connected to each other (their values depend on each other with some logic involved).
These projects I have taken on after they were implemented, and I found a lot of events / data bind hell - what I mean by this is that because all these fields are depending on others they have implemented INotifyPropertyChanged and other fields are being modified as a result. This causes the same fields being updated 5-6 times when the screen loads and the order in which fields are populated causes horrible bugs. (For example, Date was set before Job Type, instead of after Job Type, so I end up with a different Job Fee.)
To make matters worse, some hacks are implemented on UI events (for example, DropDown changed to update field X) while others are in the domain model that the UI binds to.
Basically, it's a huge mess, and I just want to know what the best way to implement something like this is if I was to start from scratch. Or is it a good idea to avoid such a complex screen in the first place?
I would try to keep the business logic out of the property setters as much as possible.
First of all, if several properties are needed for one calculation, I'd write one method that does the calculation, and call that method when appropriate. E.g. if all different combinations of property values make sense, one could just call the method in the setters of each property, making sure that the same code runs any time one of the properties is changed. If you only can evaluate special combinations of property values, you could either implement a command and let the user decide when to calculate the resulting changes, or you could provide feedback through validation, and only evaluate the property changes if the combination is valid. If there are several interdependent properties, I often use a "ChangeInitiator" variable to indicate what property has changed, so that it is clear in the calculation method which property is responsible for the change and which others should change as a result. Basically, this is the same as doing one part of the calculation in each property setter, but I find that it helps me to keep an overview of things if the different parts of the relationship are all in one method.
In a program I wrote once, I had some calculations running on a background thread periodically, so I would just set a flag whenever a piece of data changed that required a new calculation, and do all the updates based on a timer every second or so... that could also help you get the logic more straight, and it avoids to have the calculation run several times for one set of related changes.
With regard to change notification, I'd really try to only use it for UI data binding.
We have fairly complex UIs (including several related fields of different types in, say for example a Row in a DataGrid) and the MVVM pattern has worked pretty well for us. All the properties coming from the Model and exposed to the View that have complex logic related are "wrapped" by an equivalent property in the ViewModel, which has no Backing Field, but rather points directly to the Model:
public class SomeComplexViewModel
{
public SomeModel Model {get;set;}
public string SomeCrazyProperty
{
get
{
return Model.SomeCrazyProperty;
}
{
Model.SomeCrazyProperty = value;
//... Some crazy logic here, potentially modifying some other properties as well.
}
}
}
<TextBox Text="{Binding SomeCrazyProperty}"/>
This removes the "initial value" problem, as the initial value read by the Binding is actually the real value coming from the Model, and thus the logic placed in the Setter is executed only when needed.
Then, for dummy properties (which have no logic behind), we bind directly from the View to the Model:
<TextBox Text="{Binding Model.SomeRegularProperty}"/>
This reduces the bloat in the ViewModel.
With regard to events in the code behind, I totally avoid that. My code behind files are almost always one InitializeComponent() and nothing else.
Only View-Specific logic is placed in the code behind (such as animations stuff, etc), when it cannot be directly done in XAML, or is easier to do in code (which is not the case most of the time).
Edit:
It's important to mention that the winforms binding capabilities are a joke compared to the XAML-based ones. could that be the cause you're seeing those horrible messes in those projects?
Edit : Accepted Chris Holmes response, but always ready to refactor if someone come up with a better way! Thanks!
Doing some winforms with MVP what is the best way to pass an entity to another view.
Let say I have a CustomerSearchView/Presenter, on doubleClick I want to show the CustomerEditView/Presenter. I don't want my view to know about the model, so I can't create a ctor that take an ICustomer in parameters.
my reflex would be,
CustomerSearchView create a new CustomerEditView, which create it's own presenter.
Then my CustomerSearchView would do something like :
var customerEditView = new CustomerEditView();
customerEditView.Presenter.Customer = this.Presenter.SelectedCustomer;
Other possible approach would be a CustomerDTO class, and make a CustomerEditView that accept one of those CustomerDTO, but I think it's a lot of work something simple.
Sorry for basic question but all example I can find never reach that point, and it's a brownfield project, and the approach used so far is giving me headache...
I don't know exactly how you are showing your views, so it's a bit difficult to give you specific advice here. This is how I've done this sort of thing before:
What we did was have the CustomerSearchViewPresenter fire an event like OpenCustomer(customerId). (That is assuming that your search view only has a few pieces of Customer data and the customerId would be one of them. If your search view has entire Customer objects listed then you could call OpenCustomer(customer). But I wouldn't build a search view and allow it to populate with entire objects... We keep our search views lightweight in terms of data.)
Somewhere else in the application is an event handler that listens for the OpenCustomer() event and performs the task of creating a new CustomerEditView w/ Presenter (and I'm going to defer to my IoC container do this stuff for me, so I don't have to use the "new" keyword anywhere). Once the view is created we can pass along the id (or customer object) to the new CustomerEditView and then show it.
This class that is responsible for listing the OpenCustomer() event and performs the creation of the CustomerEditView is typically some sort of Controller class in our app.
To further simplify this situation, I've done this another way: I create both the CustomerSearchView (& presenter) and CustomerEditView (& presenter) when the application or module starts up. When the CustomerSearchView needs to open a Customer for editing, the CustomerEditView becomes the responder to the OpenCustomer event and loads the data into itself, and knows how to show itself in whatever container it is supposed to do.
So there's multiple ways to do this.
How about:
//In CustomerSearchPresenter
var presenter = new CustomerEditPresenter();
var customerEditView = new CustomerEditView(presenter);
presenter.SetCustomer(customer);
//In CustomerEditPresenter
public void SetCustomer(customer)
{
View.Name = customer.Name;
View.Id = customer.Id;
...
}
In think your customer search view should just delegate to its presenter you need to have an action execute.
There are a couple of crucial insights to get a natural flow in any MVP code:
It's the presenter that drives the view, not the other way around.
Because of 1. the view need not know about the presenter's existence. Less dependencies usually means easier maintenance.
In C#, I find events being a great asset when decoupling presenters from views. More details in a previous answer: Model-View-Presenter in WinForms
I would look at MS Prism 4, and their nice Navigation interface. Also look at Silverlight and WCF Navigation. They are well done and handle things like prompting the user for confirmation from "dirty" forms, with cancellation.
I would look at the PageFunction() documentation in WCF as well, for how to "call" a page from another, and get back info.
Here's how it works (javascript, sorry):
User double-clicks customer on customer list:
CustomerList.onDblClick(customerId){
app.fireEvent('customerEditRequest', id)
}
...
app.onCustomerEditRequest(id){
this.mainRegion.requestNavigate('customers/edit', id);
}
If navigation to edit view was successful...
CustomerEditView.onNavigatedTo(context){
this.model.load(context.parameters.id));
}
CustomerEditView.onSaveButtonClick(){
this.model.save();
app.fireEvent('customerEdited', id);
}
...
app.onCustomerEdited(id){
app.mainRegion.requestNavigate('customerlist', id);
}
There are a few different ways you could do it:
send a callback function to the edit form, from the customer list. edit form will call it, and you do what you want when it's called.
have the edit form raise on "customerEdited" event that you listen to and react to (no app-wide bus)
use an application-wide Event Bus to manage the events centrally, shown.
I used to have my views communicate with their presenters, but have moved away from that. It doesn't conform to the original definition of a pattern (not a reason in itself for deviating just a contributing factor to exact those benefits). Views ideally should be kept as dumb and with as few dependencies as possible. View should communicate w/ Presenter (any "observers") via delegates/events/some "fire-and-forget" mechanism. As a matter of fact, I've introduced a controller into MVP specifically to intercept View events and either re-fire to presenter (rarely) to communite w/ Presenter, or to communicate with a system or Presenter-specific event bus - enabling me to change user action alerting mechanisms w/out touching the view. Have to be careful with an event bus though; pretty soon you start throwing all events in there, app gets chatty/bogged down in handling events, and events aren't the fastest things in .Net. Sunchronization is an added concern, esp if ur app need to have a more "conversational" interaction with your user.
Should bear in mind that although Presenter is usu view/process-specific, views (and view-models) can be reused; having the View in a containment/delegation relationship with the Presenter strongly couples View/limits its reuse. This could be reduced by some DI, but I find DI containers to be unnecessary complexity in most cases (since I have to know how to create objects anyway and how often do you change out an object for another semantically similar one after creating/testing it?). Concrete dependency goes nowhere except another layer/adds more obscurity/makes things more difficult to debug/trace. Been on a "simplicity" kick lately though, and mostly prefer to do my on Factory/object creations/ORM mappings for most apps, since there's usu a "1-to-1" btw db tables/entities and n need for the added complexity of a generic 3rd-party ORM tool that by taht generic context/needing to serve different apps has to make things harder than they need to be, even if u understand how they work (not the point).
Moreover, it's still quite feasible for View to observe Model in MVP (as in MVC), so I wouldn't be so quick to rule this out. I don't prefer to do this myself, but it' doesn't "break" the pattern. Matter of fact, I developed something similar to MVP about a decade ago because I didnt like the "circular loop" btw the MVC components (View knowing about Model); I preferred to have the cleaner separation btw View and Model that all these patterns (including MVC) professed, as well as a desire to keep View as dumb as possible (observing Model woujld mean View would need more intelligence to process Model changes). What I ended up doing was something like MVVM and strategy patter, where I used "substructures" of the model to pass in to the View, serving as "change notifiers". This kept everything view purpose-specific and flexible/reusable (tough combo).