I've found view models to be very useful for splitting user interface and business logic code. However, I've also made the experience that for small, simple windows a view model class just adds a lot of additional code, effectively reducing maintainability instead of improving it.
Let me give you a simple, real-world example that I've had recently: A dialog window providing two (fixed-text) buttons and a customizable text block.
Using plain old x:Name-based code-behind programming technique, this is a matter of a few lines of code (set the text, handle the two button clicks by returning a value and closing the window) -- clean and simple.
Doing it the "recommended way", i.e., creating a view model class (implementing INotifyPropertyChanged or inheriting DependencyObject) and defining Commands requires an awful lot of code compared to the solution above (especially since there is no concise way to define "local variable + property + raise PropertyChanged" in VB) -- making the solution less readable and more error-prone.
So, currently I'm using the pragmatic approach of choosing between "plain old x:Name" and view model on a case-by-case basis. However, the wealth of blog/forum postings claiming that the view model should be used all the time makes me wonder whether I've overlooked something.
Did I overlook something?
I'm all for MVVM, but the window you're describing can be implemented once and then filled as needed when you want to open one. So the ViewModel might look like this:
public SmallDialogTask
{
string Title { get; set; }
string Text { get; set; }
string AcceptButtonLabel { get; set; }
string RejectButtonLabel { get; set; }
Command AcceptCommand { get; }
Command RejectCommand { get; }
}
Implement this once and use inheritance to configure the various instances where you need it. As you can see from my example, this allows you to encode much more semantics into your class.
See also DRY, my question about MVVM dialogs and -- just for reference -- my blog post about MVVM.
You can use data binding without defining a view model - and in most "small" windows there isn't mush logic - so you don't actually need change notification.
Just set DataContext = this and data-bind to properties of the window class.
Commands, on the other hand, don't have good simple version so I'll just use good old event handling.
(I also think that MVVM is overkill for a lot of not-so-small windows, but I'm obviously in the minority on that one)
I do the same.
Small dialogs and quick choice or information messages just get done in the simplest possible way. I try not to overcomplicate things with patterns that are unnecessary. The main application windows and anything larger is generally done with MVVM.
(So either you haven't missed anything, or I've missed the same thing.)
I do something similar however in the situations where i just want a very small window that does something very basic i at least implement an interface and call it through a gateway so that i can call it in a testable way. Something like this :
//eg . in a viewmodel.cs or command.cs
var sometextIwantUserToEnter = UIServices.GetMeSomethingThatCan().GetText();
My window will implement IGetText and i do all the Window showing and result checking in the window itself in the GetText method. This keeps everything isolated in the window and i can assert that the service was called in my tests.
Hope that made sense.
You don't have to implement INotifyPropertyChanged in a view model class. You only need to do this if you need change notification, which, for simple dialogs, you don't.
I can't speak to VB-specific issues, but in C# the code that results is at least as simple and concise as it would be if it lived in the window's code-behind - and frequently more so, if you try to implement commanding behavior without implementing commands. ("I'll just set IsEnabled to true in this property setter, so that the OK button is enabled once data is entered," is one of those sentences where the word "just" turns out to be a damn lie.)
The counterargument to this - "sure, but if I don't implement change notification, then I can't do X and Y when something changes a property value" - undercuts the assertion that what you're building is simple.
I find that in general, nothing is as simple as I think it's going to be when I first start it. It's a lot easier to add change notification and commands to a view model class than it is to refactor a view model class out of a window's code-behind so that I can add change notification and commands to it.
Finally, if you use simple view model classes to back simple views in all cases but one, that one case is going bite you (or some other developer) in the ass someday. There's a lot to be said for consistency if the cost of consistency is low.
Related
I know this has been done to death, but most answers are along the lines of "yeah, you can use eventhandlers in place of commands if you like". This still doesn't solve the problem of whether writing complicated commands is warranted vs just wiring up eventhandlers in code behind to call testable methods in your view model.
I don't like commands because they produce a lot of boilerplate code and don't give me any benefit over normal methods, plus some of them (such as drag & drop) are a pain to implement.
What's wrong with writing:
codebehind:
private void Button_Click(object sender, RoutedEventArgs e)
{
viewModel.LoadData();
}
viewmodel:
public void LoadData()
{
//....
}
This is equally testable (if not more) as any command is. IMO, as long as UI specific stuff isn't leaking into your business logic, there's really no need to waste time on complicated patterns like that. Thoughts?
What's wrong with writing
Nothing - for the most part.
There is nothing wrong with using code behind, if you are careful to keep the business logic out of the code behind file. This is delegating this directly to the ViewModel, which is reasonable.
That being said, there are a couple of potential downfalls here in terms of long term maintainability:
By doing this, you're coupling the View to the ViewModel more tightly. While this is a reasonable thing to do (the View, in reality, always knows about the ViewModel), it does prevent potential reuse of View components in some scenarios, as using an ICommand allows you to have the same View be used with potentially different ViewModels. (This is rare in practice, however.)
This starts a slippery slope - by adding "any" code into code behind, you're opening up the potential that another developer will add "just one more line" in there. Over time, this can lead to a mess.
It's adding code into another place that has to be maintained. Now you'll have to maintain the ViewModel .cs file, your .xaml file, and the code behind file.
You're hard-wiring this logic into a Button. If you decide to change controls, use a gesture, etc., you'll have to remember to rework this logic.
I was in your boat at first, I even asked basically the same question here. But I came around and came to really like commands.
Some commands really are complex enough in and of themselves to warrant testing. They are just as testable as anything else on your viewmodel.
ICommand also includes CanExecute and CanExecuteChanged, which enables your view to intelligently enable/disable itself pretty much for free. This is fantastic in complex views.
Commands make it easier to change your view around, most controls have a Command property you can bind to, and simply moving the binding around is easier than mucking with event handlers. This is especially true if you have designers working on the XAML.
You can pretty much write the entire logic of the view without the view even existing. It leads to a nice flow of build the meat all at once, then throw the interface on top all at once.
Keeping your code in one place leads to longer term maintainability.
To me a very important argument against events is forcing the UI Designer to write code to be able to test a View. And worse: every time he redesigns the View he has to rewire the events.
Commands and the behaviors in Blend make render this process obsolete and much easier.
Another problem might arise when actually using the event arguments when writing the event handler. When you want to switch to another control or another event you might have become very dependent on the event arguments making it hard to switch because the other control/event does not support the same event arguments.
Seriously, it seems like every time I want to make my UI elements talk to each other, I end up coding a new, custom, IValueConverter :(. Someone tell me that I'm doing it wrong, please!
Examples:
I wanted a button to be enabled only if my textbox contained a valid URI. Great, time to code up a UriIsValidConverter!
Oh oops, I also wanted to disable it while I'm processing something. I guess now I need to code up a UriIsValidAndBoolIsFalseMultiConverter!
I want to display a list of files in a certain directory (specified by a textbox) inside a listbox. I guess I need a DirectoryPathToFileList converter!
Oh hey, I want icons for each of those files in the listview. Time for a FileInfoToBitmap converter!
I want my status to be red if my status-string contains "Error", and green otherwise. Yay, I get to code up a StatusStringToSolidColorBrushConverter!
I'm really thinking this isn't that much better than the old Windows Forms method of just wiring up everything manually using TextChanged events (or whatever). Which I guess is still an option. Is that what people actually do, perhaps, and I'm trying too hard to make everything fit into the databinding paradigm?
So yeah, please tell me if this is really how WPF coding is---or if I'm doing it wrong, and if so, what I should be doing.
Your approach is perfectly valid (though I would use a multibinding for the second example, rather than a such a specialised converter), though by placing all your logic into the XAML you are producing very high coupling between the way the application looks and the way that it behaves, because of this you may want to look into the MVVM pattern to separate those things out.
Under the MVVM pattern your XAML (the view) just contains very simple data bindings into a ViewModel which handles all the logic and updates the view through the INotifyPropertyChanged interface. The code for your third example may look something like:
public class DirectoryManagerViewModel : INotifyPropertyChanged
{
private string _directory;
public string Directory
{
get { reutrn _directory; }
set
{
if (_directory != value)
{
_directory = value;
OnPropertyChanged("Directory");
if (IsValidDirectory(value))
{
PopulateFiles();
}
}
}
}
public ObservableCollection<FileViewModel> Files { get; private set; }
private bool IsValidDirectory(string directory)
{
//return if the directory exists etc.
}
private bool PopulateFiles()
{
//Populate Files with files in directory
}
}
Where FileViewModel is another view model which contains the name and the icon for a file.
The advantage of this approach is that the ViewModels can be reused with other views and other technologies such as ASP.NET or Winforms so you are not locked into the WPF stack. (alos if you work in an environment where there are designers responsible for the look and developers responsible for the behaviour, this helps define those boundaries)
At the end of the day though this logic does need to go somewhere and while there are better and worse ways to architect your application you are still going to be writing code that takes a string and converts it into a series of filenames and icons somewhere.
First, you might want to start by reading about the Model-View-ViewModel pattern (MVVM). Josh Smith had a fantastic article in MSDN Magazine recently. MVVM and WPF go perfectly together. Done right, you won't need IValueConverters so much. The way that you are going about it now is causing a very tight coupling between your visualization and your application actions. MVVM is designed to decouple these elements.
In this context, your view model will track state for you. Your button will be enabled if the CanExecute method on a certain ICommand in your view model returns true. This same concept can handle disabling the button when processing something.
You want to display a list of files in a certain directory that is specified inside a listbox? Have a DirectoryViewModel view model that will handle providing the list of files to the view by binding to the view model. The display of the files can be specified with a DataTemplate specified in XAML with no code behind. This same concept can handle providing the icons to the view whose display can be specified in the template.
You want your status to be red if a status message contains "Error" and green otherwise? Let a view model handle determining the state and let the view bind to that state and now you only need an IStateConverter to convert the state to red or green appropriately (this is one of many ways to handle this problem in the MVVM context).
Get in the habit of keep data and state separate from your view and your applications will be loosely coupled, easier to design and maintain, and easier to test.
Don't know if you are wrong, just making it a lot harder than it has to be!
I use MVVM, so where you are writing customer converters, I provide a bindable property on the view model that tells the view what to do. For example:
To display a list of files, I provide a collection that contains that list.
If I want icons the object in that collection has a icon property
If I want a status to be red or green I provide a StatusColorbrush property.
By moving this logic into the view model, I get:
much simpler Xaml.
can test my view logic without the view.
This approach uses one of the strong points of WPF, it's binding capabilities.
I've made it a personal rule to inherit every UI control before using it. In a previous life I'd always considered this one of the less useful things you could do because the justification always seemed to be "I might want to change the font on all the buttons at once"... a motivation that never paid off... once... ever.
Two recent projects have changed my mind about the practice, though. In the first, we needed a consistent "ValueChanged" event so that we could easily implement a "dirty" flag on our forms without a massive switch statement to choose between a Textbox's "TextChanged" event, or a ListBox's "SelectedIndexChanged" etc. We just wanted one consistent thing to listen for on all controls, and subclassing the built-in controls bought us that pretty easily.
In the second project, every effort was made to get by with the base controls because the UI was expected to be pretty simple, but a few months in, it became obvious that they just weren't going to cut it anymore, and we purchased the Telerik control suite. If we had inherited all the controls to begin with, then changing our derived controls to inherit from the Telerik controls would have applied the changes for us globally. Instead, we had to do some searching and replacing in all the form designers.
So here's my question: What are the relative strengths and weaknesses of
Simply adding a Class, and making it inherit from a control.
Adding a new "Custom Control" and inheriting.
Adding a new "Component" and inheriting.
All three have the same effect in the end, you get a new type of Button to put on your forms. I've seen all three used by different people, and everyone seems to think that their way is the best. I thought I should put this discussion on StackOverflow, and maybe we can nail down a concensus as a community as to which one is the "right" way.
Note: I already have my personal opinion of which is "right", but I want to see what the world thinks.
If both 1 & 2 are inheriting, then they are functionally identical, no? Should one of them be encapsulating a control? In which case you have a lot of pass-thru members to add. I wouldn't recommend it.
Peronally, I simply wouldn't add extra inheritance without a very good reason... for example, the "changed event" could perhaps have been handled with some overloads etc. With C# 3.0 this gets even cleaner thanks to extension methods - i.e. you can have things like:
public static AddChangeHandler(
this TextBox textbox, EventHandler handler) {
testbox.TextChanged += handler;
}
public static AddChangeHandler(
this SomethingElse control, EventHandler handler) {
control.Whatever += handler;
}
and just use myControl.AddChangeHandler(handler); (relying on the static type of myControl to resolve the appropriate extension method).
Of course, you could take a step back and listen to events on your own model, not the UI - let the UI update the model in a basic way, and have logic in your own object model (that has nothing to do with controls).
I use composition. I simply create a new UserControl and add the controls I need. This works fine, because:
I never use that many properties anyway, so pass-through methods are kept to a minimum.
I can start with a naive approach and refine it later.
Properties for look and feel should be set consistently across the site. Now I can set them once and for all.
Ok,
So I have been stalled in my latest non-work project, trying to use WPF. I am just frankly annoyed at databinding. I thought it was supposed to make things simpler by binding data directly to the UI. But the more I learn about having to implement INotifyPropertyChanged to get things to notify the UI if they changed, seems to make the whole thing counter productive.
Am I missing something? It seems like a bunch of work and having to make the classes implemented INotifyPropertyChanged seems like a fishy way to get databinding to work.
What am I missing? I must be missing something. Please enlighten me into how to make databinding easy, or at the least straightforward.
If you want the UI be notified when the underlying data source changes, then you need some sort of notification mechanism. For WPF, INotifyPropertyChanged is that mechanism.
It's the same in Windows Forms as well, but Windows Forms also supports the old notification mechanism, where you have an event with the name <Property>Changed.
However, neither of these required these mechanisms if all you want to do is bind to the data once and display it.
If you are ok with not receiving notifications, then just bind to the data source and it will work.
Truth be told, I haven't seen that it was that bad, and think it a highly workable solution.
Take this simple, Data Model object:
Public Class SimpleItemViewModel
Implements INotifyPropertyChanged
Private _item As String
Public Property Item As String
Get
return _item
End Get
Set (value as string)
_item = value : OnPropertyChanged("Item")
End Set
End Property
Protected Overridable Sub OnPropertyChanged(propChange as string)
Raise Event PropertChanged(me, new PropertyChangedEventArgs(propChange))
End Sub
Public Event PropertyChanged(sender as object, e as PropertyChangedEventArgs)
End Class
That is easily bound to a simple Textbox via:
<Textbox Text="{Binding Item}" />
additionally, if I wanted to have a DIRTY flag, I can easily put the flag being set in the OnPropertyChanged sub, and easily determine if I need to save any user changes or not.
I have found it easiest to have a set of classes which rest between the Data Access layer and the UI which holds this stuff. You can even have your Business Logic and DAL pass these classes around rather than the atomic values.
Implementing INotifyProperty changed is not particularly difficult, seeing as it only has one member.
If you don't expect changes in the underlying object then don't worry about INotifyProperty changed, and use a Binding with Mode=OneTime.
If the underlying object can change and you want the GUI to reflect those changes, then how else can this be achieved without the kind of notification that INotifyProperty changed provides? It's not reasonable to expect a bound item to poll its binding's source.
Personally I've found WPF has taken some time to get to grips with, but now that I'm gaining comfort I'm finding it incredibly powerful and enjoyable to work with. I encourage anyone who's finding WPF challenging to stick with it.
Binding in XAML is quite easy, however, dynamic WPF data binding in code is painful and confusing.
DataBinding is the only way to implement a model-view pattern in WPF/Silverlight. Your models can be UI-stupid by implementing INotifyPropertyChanged, which isolates them from the UI. It also saves a lot of UI code when stuffing information into the UI.
Another benefit that I enjoy is the ability to further bind child controls with the same data by using the { Binding } shortcut.
First, INotifyPropertyChanged isn't the only way to get data binding to work - dependency properties work too.
Second, INotifyPropertyChanged can be implemented with just one line of code in your entity class, if you use AOP - you don't actually have to do all those notification calls yourself.
Overall, I'd say data binding is a great boon, especially when you're doing code generation to make automatically bound controls from some data source.
If you're looking for a good way to think about structuring your data binding, then aim to set a DataContext on your logical tree only once, then use binding paths to populate the various parts of your UI.
Be as declarative as you can in your binding. Let the template system do it's job and make heavy use of DataTemplates that specify explicit DataTypes.
I have an MVVM application. In one of the ViewModels is the 'FindFilesCommand' which populates an ObservableCollection. I then implement a 'RemoveFilesCommand' in the same ViewModel. This command then brings up a window to get some more user input.
Where/what is the best way to do this whilst keeping with the MVVM paradigm? Somehow
doing:
new WhateverWindow( ).Show( )
in the ViewModel seems wrong.
Cheers,
Steve
I personally look at this scenario as one where the main window view model wants to surface a task for the end user to complete.
It should be responsible for creating the task, and initializing it. The view should be responsible for creating and showing the child window, and using the task as the newly instantiated window's view model.
The task can be canceled or committed. It raises a notification when it is completed.
The window uses the notification to close itself. The parent view model uses the notification to do additional work once the task has committed if there is followup work.
I believe this is as close to the natural/intuitive thing people do with their code-behind approach, but refactored to split the UI-independent concerns into a view model, without introducing additional conceptual overhead such as services etc.
I have an implementation of this for Silverlight. See http://www.nikhilk.net/ViewModel-Dialogs-Task-Pattern.aspx for more details... I'd love to hear comments/further suggestions on this.
In the Southridge realty example of Jaime Rodriguez and Karl Shifflet, they are creating the window in the viewmodel, more specifically in the execute part of a bound command:
protected void OnShowDetails ( object param )
{
// DetailsWindow window = new DetailsWindow();
ListingDetailsWindow window = new ListingDetailsWindow();
window.DataContext = new ListingDetailsViewModel ( param as Listing, this.CurrentProfile ) ;
ViewManager.Current.ShowWindow(window, true);
}
Here is the link:
http://blogs.msdn.com/jaimer/archive/2009/02/10/m-v-vm-training-day-sample-application-and-decks.aspx
I guess thats not of a big problem. After all, the Viewmodel acts as the 'glue' between the view and the business layer/data layer, so imho it's normal to be coupled to the View (UI)...
Onyx (http://www.codeplex.com/wpfonyx) will provide a fairly nice solution for this. As an example, look at the ICommonDialogProvider service, which can be used from a ViewModel like this:
ICommonFileDialogProvider provider = this.View.GetService<ICommonDialogProvider>();
IOpenFileDialog openDialog = provider.CreateOpenFileDialog();
// configure the IOpenFileDialog here... removed for brevity
openDialog.ShowDialog();
This is very similar to using the concrete OpenFileDialog, but is fully testable. The amount of decoupling you really need would be an implementation detail for you. For instance, in your case you may want a service that entirely hides the fact that you are using a dialog. Something along the lines of:
public interface IRemoveFiles
{
string[] GetFilesToRemove();
}
IRemoveFiles removeFiles = this.View.GetService<IRemoveFiles>();
string[] files = removeFiles.GetFilesToRemove();
You then have to ensure the View has an implementation for the IRemoveFiles service, for which there's several options available to you.
Onyx isn't ready for release yet, but the code is fully working and usable at the very least as a reference point. I hope to release stabilize the V1 interface very shortly, and will release as soon as we have decent documentation and samples.
I have run into this issue with MVVM as well. My first thought is to try to find a way to not use the dialog. Using WPF it is a lot easier to come up with a slicker way to do things than with a dialog.
When that is not possible, the best option seems to be to have the ViewModel call a Shared class to get the info from the user. The ViewModel should be completely unaware that a dialog is being shown.
So, as a simple example, if you needed the user to confirm a deletion, the ViewModel could call DialogHelper.ConfirmDeletion(), which would return a boolean of whether the user said yes or no. The actual showing of the dialog would be done in the Helper class.
For more advanced dialogs, returning lots of data, the helper method should return an object with all the info from the dialog in it.
I agree it is not the smoothest fit with the rest of MVVM, but I haven't found any better examples yet.
I'd have to say, Services are the way to go here.
The service interface provides a way of returning the data. Then the actual implementation of that service can show a dialog or whatever to get the information needed in the interface.
That way to test this you can mock the service interface in your tests, and the ViewModel is none the wiser. As far as the ViewModel is concerned, it asked a service for some information and it received what it needed.
What we are doing is somethng like that, what is described here:
http://www.codeproject.com/KB/WPF/DialogBehavior.aspx?msg=3439968#xx3439968xx
The ViewModel has a property that is called ConfirmDeletionViewModel. As soon as I set the Property the Behavior opens the dialog (modal or not) and uses the ConfirmDeletionViewModel. In addition I am passing a delegate that is executed when the user wants to close the dialog. This is basically a delegate that sets the ConfirmDeletionViewModel property to null.
For Dialogs of this sort. I define it as a nested class of the FindFilesCommand. If the basic dialog used among many commands I define it in a module accessible to those commands and have the command configure the dialog accordingly.
The command objects are enough to show how the dialog is interacting with the rest of the software. In my own software the Command objects reside in their own libraries so dialog are hidden from the rest of the system.
To do anything fancier is overkill in my opinion. In addition trying to keep it at the highest level often involving creating a lot of extra interfaces and registration methods. It is a lot of coding for little gain.
Like with any framework slavish devotion will lead you down some strange alleyways. You need to use judgment to see if there are other techniques to use when you get a bad code smell. Again in my opinion dialogs should be tightly bound and defined next to the command that use them. That way five years later I can come back to that section of the code and see everything that command is dealing with.
Again in the few instances that a dialog is useful to multiple commands I define it in a module common to all of them. However in my software maybe 1 out of 20 dialogs is like this. The main exception being the file open/save dialog. If a dialog is used by dozens of commands then I would go the full route of defining a interface, creating a form to implement that interface and registering that form.
If Localization for international use is important to your application you will need to make sure you account for that with this scheme as all the forms are not in one module.