Handling SelectionChanged event for TabControlEx

Sep 3, 2010 at 5:43 AM

Hi Sacha,

What is the best way to handle SelectionChanged event for TabControlEx (or a TabControl)? I know I can use EventToCommand trigger but in one of your CodeProject posts on Cinch V2, you said that it is a bad idea to have UI related stuff (in this case SelectionChangedEventArgs) in ViewModel. I'm wondering if there is a better way to handle this.

 

Thanks

Coordinator
Sep 3, 2010 at 6:18 AM
Edited Sep 3, 2010 at 6:18 AM

Yes having UI type things in a ViewModel is not for me, though I did give people the ability to do that, as lots of people said they wanted EventArgs in the ViewModel. Crazy talk if you ask me, I have never needed the original EventArgs once. Hey ho.

 

So now you question, there is a dead simple way. You simply need to wrap a ICollectionView around the ItemsSource for you TabControl in your ViewModel, and set IsSynchronizedWithCurrentItem="true" on your TabControl and bind ItemsSource of TabControl to the ICollectionView instead of raw collection. Then in your ViewModel just hook up the CurrentItemChanged event on the ICollectionView you TabControl.ITemSource is now bound to.

Marlon has excellent post on using ICollectionView : http://marlongrech.wordpress.com/2008/11/22/icollectionview-explained/

I guess in your case if you are using CinchV2 your ICollectionView will wrap an ObservableCollection<WorkspaceData>

 

Sep 3, 2010 at 6:57 AM

Awesome!

Thanks for the prompt reply. Though I knew about ICollectionView (first time I heard about it was from Marlon's excellent article), I was thinking wrapping View<WorkspaceData> would be too much. I'm removing all my EventToCommand triggers right away. Thanks again.

Sep 3, 2010 at 7:50 AM

Hi sacha,

I'm little bit confused. How you handle e.g. MousePosition on MouseDown event in your ViewModel without EventArgs?

In my actual application I use lot of EventArgs given from EventToCommand trigger and I don't know how to handle my stuff without that.

Coordinator
Sep 3, 2010 at 4:15 PM

To be honest I have never found that I needed MouseEventArgs in my ViewModel at all, could be the nature of what we do here is different. I find that most weird things like that I solve using attached behaviours..But hey, if it helps you to use EVentArgs in your ViewModels go for, but how are you going to test that stuff?

If you put it in attached props, and keep your ViewModel blissfully unaware of such things, it does make it infinitely more testable.

 

Sep 3, 2010 at 4:23 PM

Hi dimax,

After today's refactoring, I've only one place where I'm using EventToCommand trigger (where I've to bind with an event from a custom user control). I'm not sure about handling 'low level' event handling such as Mouse Up/Down but most of the events can be handled gracefully without using EventToCommand trigger; just by only using ICollection (of course if you are binding to a collection). Also, may be you want to refactor your code to see if there is any design flaw. I would rather not handle mouse up/ down in ViewModel because ViewModel class is just sort of a data generator for the View. May be you need to pull some codes out of your VM and put it in the code behind class.

I'm also interested in seeing what Sacha has to say about all these.

just my 2 cents

Sep 3, 2010 at 4:29 PM
Edited Sep 4, 2010 at 1:09 AM

{Removed}

Sep 3, 2010 at 10:29 PM

 Hi all,

I don't speak about Collection event problems. How to handle this I learned from great Cinch Demo and ICollectionView. My current project is a CAD project, so I need to handle a lot of mouse and key events. I need position, I need deltas, I need key modifier and so on. I'm not so skilled in WPF and test stuff. But I understand what you mean now sacha. It's really possible to pass the event values with some kind of behavior or attached property to the ViewModel. So at the end I use EventToCommand trigger on simple stuff and attached behavior on more complex things.

Can you really give us a good example how you handle events and event arguments in your ViewModels.

The best way sacha is, to send you my base project. You can take a look on it, if you have a little bit time, and say what you think about it and maybe you will found some points, what I can do better.

I send you an email

Coordinator
Sep 4, 2010 at 7:42 AM

Dimax

Like I have said before I do not use EventArgs in my ViewModels at all. I would use attached properties/behaviours to deal with this, and would ALWAYS want to call something that I could call from a Unit test such as a ICommand. If you are pretty certain you can mock the items in the EventArgs classes that you are expecting EventToCommandTrigger to pass in go for it. Otherwise I seriously would avoid EventArgs in my ViewModel, I would prefer to pass in some class that I could easily provide a test double for.

But as I have also said, I seem to be in the minority here, people seem to go crazy for EventArgs in their ViewModels, so I do provide for that with my EventToCommandTrigger....People wanted it, so I allowed it, doesn't mean I personally agree, but there you go.

I think my rule would be if I can mock it, then its ok to be used in my ViewModel. I guess things like EventArgs are ok to be mocked as they have public constructors etc etc, but I have seen some people use things like ListViewItem in their ViewModel, which I think misses the point entirely.

 

Sorry to say I do not have any free time to look at your code right now, but my opinions on this are clearly laid out above.

Sep 4, 2010 at 12:34 PM

Thank you sacha and no problem. I never wanted, that you look at my hole code. Just want to know what you say about my project it self, and maybe some Event issues.

Maybe you found the time to just run the Gorod.Demo application and take a look on it.

Dima

Coordinator
Sep 4, 2010 at 7:56 PM

Are you saying you have sent me a demo project? I have not received any code from you? Not sure what you mean.

Sep 4, 2010 at 10:05 PM
Edited Sep 4, 2010 at 10:18 PM

Hm

I send my project on sacha.bar...(AT)gmail.com.

Is it wrong one?

 

Coordinator
Sep 5, 2010 at 7:01 AM

no that is correct, was it zip file, gmail doesnt like zip, so maybe rename file to something other than zip and send

Sep 5, 2010 at 7:30 AM

On the way.

It was a zip file

Coordinator
Sep 5, 2010 at 7:58 AM

Dimax,

 

Got it, looks like you are doing an excellent job. I really don't have any comments really. As I say I don't like EventArgs in my ViewModel, I would rather use an attached property which I would hook up event in, and then call some command, passing it a data class that represents the EventArgs. But that is just me.

 

If you stick with EventToCommand stuff, no problem as long as you can create all the EventArgs you use in your ViewModel in Unit test code.  

 

Of course all of this only matters if you intend on writing unit test code, if you don't don't worry about it.

 

Sep 6, 2010 at 4:10 PM

Hi sacha,

I have some problems with ICollectionView and sort.

In my application I have a Collection of points. Each point is like a LinkedListItem, it have a Reference to previous and next point to easy insert or remove points from inside. Also I have a ListBox, that shows me the points in the right chain order, so it have a SortDescripion on Index that looks like
     return Previous == null ? 1 : Previous.Index + 1;

All works fine on adding new points at end or inside, the ListBox sorts items correctly, but if I delete some points and then do Undo of that action, the points comes back with right Index but not sorted and I need perform refresh of the CollectionView manually.

Ok, I can do this refresh on undo redo, but the Undo/Redo function is implemented in the application platform and don't have any known or reference of the points.

I think the CollectionView "don't forget removed items" and if they comes back it "thinks" there is nothing to do.

So did you know what the problem is and if so, how to solve it?

Thanks,
Dima

Coordinator
Sep 7, 2010 at 6:39 AM

Not a problem I have seen before, but here are a few things to try.

 

1. Is LinkedListItem implementing IComparable<T>

2. Is the Collection ObservableCollection<T>, if so you could hook up to CollectionChanged event, and recreate the ICollectionView again

Otherwise I do not know

 

Sep 7, 2010 at 8:22 AM

It's absolute strange behavior,

I added IComparable and on CollectionChanged event I clear SortDescriptions first, refresh the CollectionView, add SortDescriptions again and refresh View second time.
Nothing helps.

If I add a new Point it sorts all correct again.

Sep 7, 2010 at 9:15 AM

I found the solution for my problem, but it's an absolute hack.

After undo/redo action, if the Points Collection was changed, I add and remove a dummy Point to the Collection. Then the ListBox shows correct sorted list.

So it looks like to perform sort refresh the CollectionView needs an absolute new item and old, removed one is maybe still in memory on the same place and so CollectionView do nothing.

But I don't really like this solution.

 

Coordinator
Sep 7, 2010 at 10:29 AM

Does sound weird, I think if you can create brand new collection and ICollectionView would be best

Sep 7, 2010 at 2:17 PM

This ListBox DataContext is a ViewModel, witch holds Points from ActiveDocument. I create ReadOnlyObservableCollection of this points and ListBox ItemsSource bind on it.

I tried to recreate ROOCollection and CollectionView, but nothing helps. Collection still need an absolute new Item to perform full refresh.

On undo action items comes back and View refreshes but not sorting.

Maybe I found time and create small project with the same behavior.

Coordinator
Sep 7, 2010 at 3:28 PM

Yeah sounds like you would do well to try it in isolation