I am currently looking to implement drag & drop functionality in a Silverlight 4 application (in this particular case a treeview) using MVVM (and CSLA 4.0.1). So far I found a number of examples for Silverlight including the folowing:
but none of them make use of MVVM, just XAML and code behind. The link http://forums.lhotka.net/forums/p/6742/32511.aspx was very helpful but does not provide any indication on the binding for the UI or MVVM usage.
Please help. Any lead would be appreciated.
I haven't tried to do this, so I can't provide a specific answer.
But I can offer some general guidelines.
First, you need some way to route arbitrary UI events to your viewmodel. This is what the CSLA (or Bxf) TriggerAction control does for you.
Second, sometimes you need some way to cause the UI to do something that would normally be a method call on a UI control, but with MVVM it has to be something triggered by a property changing in the viewmodel. I usually work around this by creating an attached property that knows how to bind to a property, and how to call a method on the UI control when that property changes. This attached property is purely part of the View.
For example, I use this second technique to integrate the Silverlight navigation framework with MVVM, because navigating to a new page requires a method call, but my viewmodel just exposes a URI property and sets that property to the page to be displayed. My attached property sees that the URI property has changed, and calls the Navigate method on the UI frame control.
This is in the Bxf Silverlight sample named UsingBxfNav (http://bxf.codeplex.com).
OK... I'm going to ask a question that is very thinly related to the OP, so if I need to move this to a new post, then let me know.
(And, for those who are confused, the "you" in this is Rocky...)
As I muddle through my thoughts on MVVM, I understand your goal of "no code-behind in views", and I understand the rationale for it. I agree with it rather wholeheartedly. However, I'm wondering if this specific instance is taking it a little too far.
While I have no problems creating the requisite "verbs" on the VM to manage the copy/move/whatever operation is defined by the drag-and-drop, I don't understand why the basics of the drag-and-drop visual work can't be done within the view. Why should I go to the trouble of creating attached properties, TriggerActions, commands, etc. to route a bunch of mouse-related events to a VM?
I ask this because I've heard discussions that you have had in this area where you've mentioned the one caveat to your rule - "UI-specific actions". Your examples in those discussions were animations. But why would this not also fall under that arena?
Again, I realize the pro's of not having code-behind in your XAML views. But a drag-and-drop operation is awfully UI-specific, and while most any control can be a drop target, realistically it only applies in a very few select situations. Yes, being able to abstract that could help if your designer changes your UI on you, but my response to that is that many users' expectations of drag-and-drop behavior are defined by the controls they are interacting with, so a change in the control set likely requires a change in the underlying DND code anyway. And given the varying kinds of drop targets (treeview nodes, listbox items, text controls) and their very different meanings, I'm not sure how you'd successfully abstract that notion away anyway...
The last response I see would be from a testing perspective. But how do you realistically test your mouse-related verbs... without a mouse? Yes, you can run tests to make sure your appropriate properties are set, but what does that really get you? That you can set VM properties in response to a method call? That hardly seems like code worth testing...
I totally realize the slippery-slope nature of the question. And I'm not surprised that finding MVVM-related examples of DND is hard, given what I see as Microsoft's view of MVVM (and how CSLA's view differs). Maybe it's enough for me to say "this is my line in the sand" and be done with it. But if I'm going to use CSLA in my programming, some level of "compliance" is realistically required in these areas, and to be honest I would have a hard time justifying this situation to another developer if asked without some form of "because I said so"...
What am I missing? Or am I completely mis-understanding?
I do think this can get tricky, because there is some grey area here...
In my mind the goal for a viewmodel should be that it is a business focused presentation construct. In other words, it shouldn't be a simple replacement for code-behind (other than to enable testing maybe), but instead should exist at a higher level of abstraction.
So instead of an Item_Click method, it should have things like a ShowDetail method. What happens when you "show detail" could be quite different on a phone vs a tablet vs a 50 inch screen, so the abstraction is useful.
But in my navigation example, there are a couple things going on. There are all sorts of UI gestures that might cause navigation to a new view - all of which can be abstracted by methods in a viewmodel (such as ShowDetail). Of course the viewmodel needs an abstract way to navigate, such that at runtime the Frame control's Navigate method is called, and at test time there's no attempt by the viewmodel to interact with the Frame conrol (because it isn't even there at test time).
And this brings us down to brass tacks. We can talk about a fine line between "pure view" and less pure presentation/navigation code or whatever. But at the end of the day the goals are to be able to test the code in the viewmodel, and to test as much code as possible.
Code behind a view can only be tested by a human - so that's expensive and error-prone.
Code in a viewmodel can be tested using automation. BUT ONLY IF all interaction with any actual UI or view types is abstracted away. In other words, a viewmodel can NEVER do something like MessageBox.Show or CurrentFrame.Navigate(url) - because those things make the viewmodel untestable.
Back to my navigation example, the viewmodel needs to be able to initiate navigation, but it can't call the Navigate method. So something needs to sit between the XAML and the viewmodel to hear the viewmodel's PropertyChanged event and to call the Navigate event (at runtime), or to record the attempt to navigate (at test time).
With drag-and-drop I totally see what you are saying. And if the drag-and-drop functionality only needs to interact with the viewmodel or model at the point of drop completion (for example), then putting the code in code-behind is arguably better because there is no business abstraction for the drag-drop concept that would belong in the viewmodel.
I guess I'm kind of rambling - my head is in a different space (working on the data access book) - so I'm not very focused...
In short - I still think code-behind should be avoided if at all possible, and I'd rather write some helper controls or attached properties to minimize code-behind. But the viewmodel should consist of abstract business task oriented verbs, and shouldn't be an event handler replacement for the code-behind.
Custom controls, attached properties and the viewmodel - these are all far more testable than code-behind. That, and custom controls and attached properties can be used by the UI designer, while they probably can't write or fix code-behind as they rework the UI over time.
Copyright (c) Marimer LLC