Managing Cancelable Partial Updates using MVVM - c#

I’m new to MVVM and am trying to establish good practices as I convert a large non-Model-View WinForms project. Here’s an example of a solution I’ve implemented. I’m wondering if there is a better pattern for solving this class of problem.
MyModel has ten properties. MyView exposes two of them for users to update. MyViewModel handles the usual stuff in between.
Other models depend on MyModel’s properties, so I only want to change MyModel when values are committed to. MyView has OK and Cancel buttons, so instead of having MyViewModel directly update MyModel when the user interacts with MyView, I’ve created another layer: MyTempModel. MyTempModel contains two properties which correspond to the two from MyModel.
So inside MyModel, prompting code looks something like this:
var tempModel = new TempModel{Prop1=Prop1,Prop2=Prop2};
bool? response = new MyView().ShowDialog();
if (response.HasValue && response.Value)
{
Prop1 = tempModel.Prop1
Prop2 = tempModel.Prop2
}
Thus if the user clicks ‘Cancel’, MyModel’s properties are not changed.
Note: Not shown here is that I set a reference to MyTempModel in MyViewModel once to establish that wiring. MyViewModel subscribes to property changed events in MyTempModel and MyView uses databinding to connect to MyViewModel.
model - > view data flow summary:
MyModel sets property in MyTempModel, which fires an event. MyViewModel’s evenhandler picks up the change and sets a dependency property, causing MyView to update.
view -> model data flow summary:
Changes to MyView result in dependency property in MyViewModel to change. This property’s setter pushes the value to MyTempModel. When user clicks Ok then MyModel copies values from MyTempModel.
I'm particularly interested in the role of the ViewModel. I have in mind that keeping dialogs "humble" is a good thing, and maybe that is spilling over into making ViewModels humble. So comments on what kind of functionality you put into your view models vs your domain models would be especially interesting.
I appreciate any and all design wisdom for this pattern. I'll gladly update this info if anyone needs clarification.

I don't think the use of a proxy class is a bad thing. I'm a little concerned about this: 'MyModel sets property in MyTempModel, which fires an event. MyViewModel’s evenhandler picks up the change and sets a dependency property, causing MyView to update.' I think that renders your Model classes a little less universal and obscures that functionality from the ViewModel. I would just use the ViewModel to mediate the swap in/out of the proxy, rather than having the Models do it. I also think that using a proxy opens up use of DataTemplates for that type which could make the UI work easier.

An alternative to the direction given by Alex is to make the viewmodel a representation of what is in both client and server side.
E.g., the number shown is always what the user entered and the background of the number indicates that this number has been confirmed or not (pending)by the server. The viewmodel could use two different properties to contain these values and a status property to indicate the fact the property has been synchronized.
This way the viewmodel captures all the user needs to know. All the view needs to do is bind to the correct properties for display and editing.

Related

How can I pass in parameters from one to another ViewModel for its View to use?

I have an app that should display data based on variables from parameters received from calls of the ViewModel.
I have noticed two places in which the ViewModel gets called from, one is the intended call by the parent ViewModel for displaying the View of the child ViewModel with the help of ViewLocator.cs. Another is the DataContext required by the View to enable data binding.
Former: [ParentViewModel.cs]
public ParentViewModel()
{
UserControlContent = new ChildViewModel(genericParameter: "actual parameter");
}
Latter: [ChildView.axaml.cs]
public ChildView()
{
InitializeComponent();
DataContext = new ChildViewModel(genericParameter: "not the parameter I want");
}
So I want to pass in the "actual parameter" as shown above for show in the resulting View. I expect the final view to look like this:
But in reality I get this:
So, how can I work around this and get the View to display the right data?
Appreciate any input!
Turns out, only the call from the ParentViewModel is required. DataContext under ChildView can be removed and the correct parameter can be used.
Thanks to the answer here for this question.
I think you have some fundamental misunderstandings of MVVM.
Firstly, you have two ChildViewModel instances.
So calls made in your ParentViewModel on the UserControlContent instance of the view model will never be reflected in the UI as the ChildView creates a new instance of the ChildViewModel itself and then uses this instance for as it's DataContext.
You should make use of some form of IoC and DI your dependencies.
MVVM discourages the use of manual view model creation through the new keyword.
Unless there is a very specific use case, try to keep some relationship between the UI structure and your view models as flat as possible.
By this I mean if there is a use case where the parent view model needs the same things as the child view mode. It may make sense to flatten and merge those two view models.
This in turn simplifies the VMs themselves and the bindings.

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.

What is in ViewModel in MVVM [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I have spent long time searching about MVVM in WPF. I understand why to use it. This is clear for me.
What I don't is, what is in ViewModel itself. I know it is the connection between the View and the Model. Also, I know (at least, what most of programmers suggest) that implement the INotifyPropertyChanged. Adding to this, the Commands.
Let say, that I have this Model (Code First with EF 6):
public class City
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int CityId { get; set; }
[DataType("VarChar"), MaxLength(25), Required]
public string CityName { get; set; }
}
My Questions are:
1- In many examples I've seen, they recreate the same fields again in VM. What is the purpose, is it enough to have the whole object (City in my example). How about if there are many fields!.
2- To be able, to use it in my View (CRUD), how is the CityVm() will be in my example?.
I appreciate any help.
The view model in the MVVM pattern encapsulates the presentation logic and data for the view. It has no direct reference to the view or any knowledge about the view's specific implementation or type. The view model implements properties and commands to which the view can data bind and notifies the view of any state changes through change notification events. The properties and commands that the view model provides define the functionality to be offered by the UI, but the view determines how that functionality is to be rendered.
The view model is responsible for coordinating the view's interaction with any model classes that are required. Typically, there is a one-to many-relationship between the view model and the model classes. The view model may choose to expose model classes directly to the view so that controls in the view can data bind directly to them. In this case, the model classes will need to be designed to support data binding and the relevant change notification events.
The view model may convert or manipulate model data so that it can be easily consumed by the view. The view model may define additional properties to specifically support the view; these properties would not normally be part of (or cannot be added to) the model. For example, the view model may combine the value of two fields to make it easier for the view to present, or it may calculate the number of characters remaining for input for fields with a maximum length. The view model may also implement data validation logic to ensure data consistency.
The view model may also define logical states the view can use to provide visual changes in the UI. The view may define layout or styling changes that reflect the state of the view model. For example, the view model may define a state that indicates that data is being submitted asynchronously to a web service. The view can display an animation during this state to provide visual feedback to the user.
Typically, the view model will define commands or actions that can be represented in the UI and that the user can invoke. A common example is when the view model provides a Submit command that allows the user submit data to a web service or to a data repository. The view may choose to represent that command with a button so that the user can click the button to submit the data. Typically, when the command becomes unavailable, its associated UI representation becomes disabled. Commands provide a way to encapsulate user actions and to cleanly separate them from their visual representation in the UI.
To summarize, the view model has the following key characteristics:
The view model is a non-visual class and does not derive from any WPF base class. It encapsulates the presentation logic required to support a use case or user task in the application. The view model is testable independently of the view and the model.
The view model typically does not directly reference the view. It implements properties and commands to which the view can data bind. It notifies the view of any state changes via change notification events via the INotifyPropertyChanged and INotifyCollectionChanged interfaces.
The view model coordinates the view's interaction with the model. It may convert or manipulate data so that it can be easily consumed by the view and may implement additional properties that may not be present on the model. It may also implement data validation via the IDataErrorInfo or INotifyDataErrorInfo interfaces.
The view model may define logical states that the view can represent visually to the user.
This is a pretty broad topic based a lot on opinion. The MVVM model isn't a set-in-stone thing, and there's lots of different ways of implementing it.
The ViewModel, in my opinion, has two main purposes:
1) To expose the Model to the View. There's two ways of doing this. Having your Model wrap your CRUD object and manage NotifyPropertyChange. In this case, it's common for your ViewModel to just expose the Model to the View and not do much else with it, the View binding directly to the Model, or via simple pass-through properties.
The other common scenario is just to have your model as a CRUD. In this case, the ViewModel manages the NotifyPropertyChange notifications and manages model updates, etc.
2) To manage Presentation logic and data. There's lots of things that you need to bind to and store that have no place in the Model. The Model is the data. It's most likely loaded from a database. Yet the View needs to track other properties. An example: say your city object is displayed in a list, and you want to show or hide it with a button. The logic for hiding it, and the boolean for it being hidden doesn't belong in the View, and has nothing to do with the base data in the Model, so it sits in the ViewModel.
Similarly, maybe you have a CityPopulation property. In your view you want to highlight cities that are larger than 1,000,000 population in red. Your View Model has the a property:
bool LargeCity
{
return CityPopulation<1000000;
}
And you render the label with a style trigger.
Another example, a ViewModel containing a Brush property to bind to, which I think is probably a common but bad practice. slugster also comments below that visual elements should not be present in the ViewModel.
Brush HighlightBrush
{
get
{
if (CityPopulation<1000000)
{
return Brushes.Red;
}
else
{
return Brushes.Black;
}
}
1- In many examples I've seen, they recreate the same fields again in
VM. What is the purpose, is it enough to have the whole object (City
in my example). How about if there are many fields!.
Since the view model is the responsible of implementing view's logic and it performs actions against the model, there're some cases where some properties wouldn't be necessarily part of the model, but they're just there to serve view's requirements.
For example, let's say your model has a Name and Surname, and you want to show a concatenation of both properties in your view. You may be able to implement this using binding expressions or implementing a property in your view model:
public string FullName => $"{Model.Name} {Model.Surname}";
2- To be able, to use it in my View (CRUD), how is the CityVm() will
be in my example?.
This question has no specific answer. But you'll need a Model property at least to store a given City.

How to forbid automatic databinding on validation error

I'm creating a simple database application in C# WPF using MVVM as Relay Commands and databinding. For in-memory storage of database content I use ObservableCollection, which is binded to the Datagrid as follows:
<DataGrid ItemsSource="{Binding Path=Softwares, Mode=OneWay}" SelectedItem="{Binding Path=SoftwareSelection, Mode=TwoWay}">
when the item is selected user can chose to edit it. For editation a form is opened with a bunch of textboxes with the data of given entity. All the fields are validated using IDataErrorInfo, unless all textboxes are valid, the ok button is not enabled, and therefore no changes can be saved to the collection and to the database.
Here is how the example textbox looks like:
<TextBox Text="{Binding Name, Mode=TwoWay, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged, ValidatesOnExceptions=True}"/>
But the tricky part is, in case I change some values in textboxes and then close the window, the new values are propagated to the ObservableCollection, which I don't want to. Do you have any idea, how to prevent such behaviour? I would like the databinding work only after clicking the button. Otherwise the databindng works well, so as the button (dis/en)abling and reflecting changes to the database and to the collection after clicking. Both views are serviced by different ViewModels, data between views are passed by firing events.
I tried to add to the DataGrid UpdateSourceTrigger=Explicit to the ItemsSource binding, but didn't help. Perhaps, I'm missing some application logic?
Thank you very much for your help.
This is where most WPF developers make mistakes of assumptions!
In MVVM dirty data can be stored in the ViewModel and that's what the layer of VM is for! It mimics the View from Model's perspective and because View is in error, the ViewModel would also be in the error. Thats perfectly valid.
So having said that, the question remains
How will you NOT allow the temporary / dirty data to flow to your
ObservableCollection?
Two ways...
If your ObservableCollection is specific to your model class (say MyItem) then if your Model class (MyItem) is an Entity class \ DAL class \ NHibernate class create a wrapper of MyItem class called ViewModelMyItem and then instead of ObservableCollection<MyItem> use ObservableCollection<ViewModelMyItem>.
This way dirty data from your View would be inside ViewModelMyItem and it can only be legitimately flown back to your model class (MyItem) ONLY when Save button is clicked. So that means in Save Command's Execute() delegate you can copy \ clone the ViewModelMyItem's properties into Item's properties, if validations in ViewModelMyItem are fine.
So if Item is an EntityType class / NHibernate class / WCF client model class, it would always only valid data as ViewModelMyItem is filtering the temporary / dirty information upfront.
You could use Explicit binding model. It stops the TwoWay data to flow back to the sorce Item unless BindingExpressions.UpdateSource() is explicitly called.
But according to me, this defeats MVVM in straightforward way because ViewModel will not have what UI is showing! Still however you can use *Attached Behavior * to govern explicit binding by staying in MVVM space!
Let me know if this helps!
You're better off putting the code into the domain object's property setter. Then synchronize with the visuals by triggering the NotifyPropertyChanged handler.
More on this topic:
http://msdn.microsoft.com/en-us/library/ms743695.aspx
http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx
Setting the Binding Mode to Explicit should require you to call the binding expressions UpdateSource() method to send changes back to your model. Because you only mentioned that you set Explicit on the DataGrid's binding, I'm guessing you only need to make sure that you have that mode explicitly set on any property that is being bound directly back to your model. Such as your TextBox's Text Binding, in the case above. That will likely fix your problem but require you to call UpdateSource() on each target's BindingExpression one way or another.
If you're using one of the mainstream ORM's (EF, Linq to SQL, etc), then chances are your Entities automatically implement INotifyPropertyChanged and INotifyPropertyChanging. Because you are sharing a reference to your single instance, all changes in your edit will be reflected in your main view and anything else Binding to that instance. As a dirtier alternative, you can just create a separate instance of the same type and manually copy the values back over when the window's dialog result is true.
The first approach requires you to manually update the bindings, the second approach requires you to manually update the values from the Edit's instance.
With some more code, I can help with your specific approach.

MVVM and DataTemplates

I had asked a question about mapping multiple view models to a single view (here). I got some good answers but I am still having some trouble applying what I learned there to my particular case.
A brief recap: I want to create a base ItemViewModelBase class that exposes properties that my view will bind to. Then I will create two specific view models, PeopleViewModel and CarsViewModel. Both of these inherit from ItemViewModelBase and implement the appropriate properties. Now, I want to be able to create a single view that will display the appropriate info based on which view model it is bound to. Since both the PeopleViewModel and CarsViewModel expose the same properties and I want the view to look the same for both of these, I only need one view.
One of the answers in my previous question suggested using a DataTemplate:
<DataTemplate DataType="{x:Type ItemViewModelBase}">
//some user control
</DataTemplate>
I am new to using DataTemplates with MVVM (and MVVM in general) so I have a few questions:
Right now ItemViewModelBase is an abstract class and I defined the appropriate properties (ItemName, Items, etc.). My Items property is an ObservableCollection:
public virtual ObservableCollection<???> Items { get; set; }
What would I put as the collection type? The classes that derive from this base class will have different lists (Person, Car). Is the base view model the right place to put the property? I do want all of the derived classes to implement it so it seems so. ANd it doesn't make sense to have Person and Car extend some base object.
Let's say I do not need any customization of my views. I would only need one View in that case. It is not clear how I would set this up. Should I create a DataTemplate for ItemViewModelBase and a single view (user control) to represent it? Right now I use Unity to register my view models and when the view is created, the view model gets injected in the view. How would I differentiate between the different view models when I try to create the view?
Basically, I don't know how to show the appropriate view when using DataTemplates. In my application right now I have a window that contains a tab control defined like this:
<Grid>
<TabControl TabStripPlacement="Left" ItemsSource="{Binding TabItems}"/>
</Grid>
The TabControl's style contains the below setters:
<Setter Property="Header" Value="{Binding Header}"/>
<Setter Property="Content" Value="{Binding Content}"/>
TabItems is defined like so:
public ObservableCollection<ConfigTabItem> TabItems { get; set; }
TabItems.Add(new ConfigTabItem() { Header = "People", ResolveView = (Func<object>)(() => (PeopleView)Container.Resolve(typeof(PeopleView), "peopleView")) });
TabItems.Add(new ConfigTabItem() { Header = "Cars", ResolveView = (Func<object>)(() => (CarsView)ConfigurationModule.Container.Resolve(typeof(CarsView), "carsView")) });
So as it stands right now, I have separate view models and views for People and Cars, and whenever a tab is clicked, the appropriate view is resolved.
I want to change this setup to use the above mentioned base view model class and single view with DataTemplates.
Any sample code/sample would be greatly appreciated, showing a base view model class, some other view model classes extending that base view model, and then being able to show the appropriate view based on the view model (where there is only one generic view).
You are asking too much in a single question IMHO. Try getting your code to work with or without DataTemplates (make it hacky if you need to) and then focus on ONE area of the code that you think needs refinement, and post a question about how to solve a specific problem. I started typing out an answer and it quickly got too complicated to articulate an overall recommendation.
I'm not sure you got good advice in the other question about DataTemplates. I'm also very concerned about how you have the ConfigTabItem set up--it seems to be a parent viewmodel that uses the container (directly, which is not a good practice) to resolve a view, which presumably also has its own viewmodel. This seems needlessly complicated.
Anyway, again, try to distill it down to a few focused questions. In the case that any of it is helpful, my original start at an answer is below (unedited):
First, I'm not sure I understand the answer you were given in your previous question that talks about DataTemplates. If you will always be binding to a ItemViewModelBase, I'm not clear on why you need to specify a DataType (or even a DataTemplate). This is not to say that using a DataTemplate is a bad idea, but I'm not sure I see the necessity of it in this case.
I'm also going to say that I'm not sure I see the necessity of inheritence either. Databinding works at runtime, and outside of switching a DataTemplate based on VM type (which, as I said, I don't think you need), the view doesn't care what it is binding to, so long as the properties it is looking for are found at runtime.
So as a general matter, I would start with ONE concrete implementation of your view model. Get it to bind correctly, and then determine which parts of it you can abstract into a base class or interface if that's the approach you want to take. It's not necessary, but might help make the requirements for binding easier to "enforce"--for example, using the base class or interface will restrict you (or someone else) from changing the name of a property needed for binding.
What would I put as the collection
type? The classes that derive from
this base class will have different
lists (Person, Car). Is the base view
model the right place to put the
property? I do want all of the derived
classes to implement it so it seems
so. ANd it doesn't make sense to have
Person and Car extend some base
object.
If you are going to use a base class or interface for your VM and you want the collection to be a part of it, it can simply be of type ObservableCollection<object>. The items added to it will need to all have property names that match what you reference in your XAML. So you can't have "PersonName" and "CarName" properties if you want only one view; you would need to use something more general like "ItemName" (unless you use DataTemplates with DataTypes--this is where that actually would be useful). Again, you don't need each collection item to inherit from a base type or implement a common interface, unless (again) you want enforcement at compile time.
Look at the Architecture from Microsoft App Studio for universal apps. According to Microsofts App Studio the DataTemplates should live in a DataTemplates Subdirectory under the Views Directory. A Universal app has this directory for both the Windows UI as for the Windows Phone UI so its not in the Shared project because they are not the Same. Don't use the Converge PRISM architecture. Its completely wrong designed! That was not written with a Windows and a Windows Phone architecture in mind but like they call it Converged. It should have been completely redesigned like it works in Microsofts App Studio. Don't look for Dependency Injection its not in it and not needed. Most use Dependency Injection for stub or fake interfaces. The DataContext for design data works now so good with json data that a Dependency Injection component would be overkill.

Categories

Resources