C# extending a class in MVVM design pattern (WPF) - c#

I have a View that contains a GridView object and a ViewModel that the View represents. Now, I'd like to override the controls in that ViewModel so that I keep the same GUI but with different business logic (i.e. contained within the ViewModel). What's the proper way of doing that?
I'd assume it is not as simple as extending the ViewModel since there's the issue with its GUI being represented in the View (which has a XAML component).
Any thoughts?
Thanks.
Edit: Fixed typo

What I tend to do, is create a Base ViewModel Class with the standard UI and Control logic in it.
I then set whichever Functions / Subs I want to control individually to overrideable. But I populate them up with default code, such as The standard Form State (Editting/Adding/Deleting) code. Any I want to force to be Overridden are set to Must Override of course.
Then, I create a Individual View-Based ViewModel, inherit from the Base ViewModel Class, override the methods I require, and set this Individual ViewModel to be the DataContext for the View.
You can switch in which ever ViewModels you like using this method, so long as they all inherit from your base ViewModel class.
I hope this helps!

Related

MVVM Where should be the TriggerAction class

I develop WPF MVVM application that uses class which inherits from TriggerAction<UIElement> base class.
public class DropTrigger : TriggerAction<UIElement> {...}
This class handle drop files event and should pass the list of files to the ViewModel bounded class.
In this case, should the DropTrigger class be in View or ViewModel?
If it should be in the view (like I think), how can I execute methods in the MVVM bounded class from DropTrigger class?
Thank you !
I cannot give you a definitive answer without seeing more of your code. The most likely case is you would have an ICommand dependency property on your DropTrigger that you bind to a ViewModel property, then you pass the files in the CommandParameter.
The Trigger is, like the behavior, neither View nor ViewModel. Create a separate project folder containing these classes.

GetView() vs property in ViewModel

I'm currently in the need of setting the SelectedIndex property of my TabControl when a certain event (IEventAggregator) takes place and thought about how I'd implement that.
I came up with 2 possibilities:
Use GetView() provided by ViewAware in order to access my TabControl and set the SelectedIndex to my value
Use a property in my associated ViewModel and bind this property to my TabControl's SelectedIndex property via XAML
Both options are working fine but I personally want to get this question answered since this is not the first time I'm wondering where to implement the functionality in such cases.
I know that the first option won't enable the Notify support but besides that: What would be the proper way?
Having a GetView() method to manipulate the view directly from the viewmodel completely breaks MVVM. You might as well just put all your logic in codebehind. The whole point of MVVM is to abstract away the actual view so that it is decoupled from the logic, and the app can be unit tested.
What if you change your mind about the tabs in the future and decide to show your multiple views some other way? You've now got to start editing your viewmodel to edit the new view instead of just tweaking some XAML.
And for unit testing you're going to have no way to mock out your TabControl.

MVVM Pattern, ObservableObject

Please, help me to understand one thing in the MVVM pattern:
For example, I need to display cities on a map.
In ViewModel I have ObservableCollection, that binded to a View ItemsSource.
ObservableCollection contains objects with type "City".
Must "City"-class be inherited from ObservableObject (I use MVVM Toolkit)? Or I should create a wrapper class, inherit it from ObservableObject, in ViewModel create new wrap-objects with data from "City"-objects and add them to the collection?
Thank you!
Assuming that your City class is in your model, and you actually need to know about changes to properties on the city object - then you should create a wrapper for it (i.e. CityViewModel). Your wrapper should listen to events that notify of any changes to the City class, and fire off the relevant Property Change notifications.
Model classes should be designed to fit with the model and should not change to suit your view - the point of having a ViewModel in the first place is to abstract your model from your view. The model should know nothing of the View.
If the properties of your City class dont change, or you dont care if they don change (and you are not a purist) then you could just expose it directly - without inheriting ObservableObject.
(Although I dont use MVVM toolkit, I cant see why in general you would need to inherit ObservableObject just because you are storing the City objects in an ObservableCollection).
The purist view however, is to wrap everything that you bind to and never expose anything from the model directly to the view.
ObservableCollection or ObservableObject has no relation with MVVM model. You can create a MVVM based application without ObservableCollection and ObservableObject (ObservableObject are used when you need to change the values of property of your class but if your application is readonly you dont even need it).
MVVM -
M-Model (business layer) , V-View (GUI), ViewModel- (Context of GUI).
When XAML works on binding. You must need a notification mechanism to notify GUI that something is changed. Now if a collection is changed means you added or removed an item from collection, you need to raise a notification which you dont need if you are working with ObservableCollection. Similarly, if your class City has a property Population which when changes need to notify GUI, that's why need to make an ObservableObject.
Hope it helps..

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.

How to get notified when something changes in a WPF window?

I have an ObservableCollection that's binded to a WPF ListView, and all the values appear correct. But how can I get a notification when something that has a 2-way binding changes?
Should I use INotifyPropertyChanged just like in Winforms? Or are there better practices to do these?
I saw some people suggesting using dependency properties online, but not sure if that's what should do.
If the class I want to add a property is a DependencyObject, I generally add a DependencyProperty. If the class is a POCO (plain old clr objects), then I implement INotifyPropertyChanged.
In generall, all my business objects are POCOs and therefore I use INotifyPropertyChanged. In the WPF world, I mostly use DependencyObjects (view models, custom controls, UserControls...) and therefore they are DependencyProperties. An exception are ViewModels representing items (to be used as items in an items source). In this case I think DependencyProperties are not very practical (Because Equals() and GetHashCode() of DependencyObjects are sealed and DependencyObject is thread-dependent).
If your class already is a DependencyObject, using DependencyProperties may give you some nice advantages: You don't have to back every value, a powerfull inheritance system, default-values, property changed callbacks per property, value coercion ... (I like DependencyProperties probably more than other people them like :)
Conclusion:
Based on the title of your question: How to get notified when something changes in a WPF window?, my way would be to add a DependencyProperty and not a clr-property because the Window is a DependencyObject. By the way, Visual Studio has a nice Snippet to create DependencyProperties.
There are really two scenarios:
1) Notifying the UI when a piece of data changes-either in the ViewModel or a Model that is bound to some UI elements (usually due to a data binding). In this scenario you'd use INotifyPropertyChanged.
Example: you have a Person object that binds it's Name to a TextBox. Person needs to implement INotifyPropertyChanged and the appropriate code needs to be attached to the Name Property's setter.
2) Creating custom UI elements where you'd want data to be bound. In this case, you'd use custom dependency properties.
Example: you have a custom UI element that spins when a certain condition is met. So you create an IsSpinning dependency property that you can bind to your ViewModel's IsLoading property. The custom control then uses the IsSpinning property to modify its behavior.
I hope that was clear...
You are right. You can use INotifyPropertyChanged or you can implement dependency properties. Personally I prefer INotifyPropertyChanged, it's more light and easyer to implement than dependency property.
I've generally used INotifyPropertyChanged for my data objects.
DependencyProperties can only be implemented on framework elements I believe.
Edit: I take that back... DependencyProperties can only be implemented on DependencyObjects (A FrameworkElement is an example of that as it derives from UIElement which derives from Visual which derives from DependencyObject).
If you have a UserControl, you may wish to implement a Dependency Property so you can Bind that Property (in XAML) to some other property. You could not do this scenario with INotifyPropertyChanged.

Categories

Resources