2.4 Feature Examples

Dec 9, 2011 at 2:46 AM

It is great to see the continued development of Catel and 2.4 adds a lot of new features.  However, I am struggling to understand how some of these features are intended to be used.  Are there examples or explanations anywhere?  Here are the ones I am especially interested in:

(+) Added ViewModelPropertyChanged event to IViewModelContainer so it is no longer required
to subscribe/unsubscribe to the view model itself in parent view model containers if
your are only interested in property changes of the view model

(+) Added DelayedBindingUpdate behavior

(+) Added DynamicEventListener to be able to subscribe to dynamic unknown events

(+) Added the possibility to inject an Action into the DoubleClickToCommand behavior to allow
the execution of a delegate when the behavior is created via code

(+) Added Focus behavior to set focus via a behavior

Any guidance is much appreciated.

Tom

Dec 9, 2011 at 8:11 AM

+1

Dec 9, 2011 at 8:58 AM

Good questions. I will number them so we can discuss specific features if you want.

1) Sometimes in the code-behind, you need to be aware of property changes of the view model. What you previously needed to to was to subscribe to this.ViewModelChanged (because the ViewModel can be changed as well), and then in each event, subscribe to PropertyChanged of the new ViewModel. Some people didn't unsubscribe and were thus causing memory leaks.

So, if you are interested in a property changed event, and you don't want to take care of the ViewModel switching, that is the event to use.

2) Allows you to delay update a binding. This is a behavior, and can be used ina textbox. For example, sometimes a user types something in a textbox, and you don't want to invoke the search command (which reacts to the property changed of the binding) on every keydown. So, with this thing, it is possible to let the user type, and when the user stops typing for, say 500 ms, you can update the binding.

For more information, see this documentation.

3) In Catel, we needed to subscribe to an event of which we did not know the handler type of on forehand. For example, the PropertyChangedEventHandler does not follow the EventHandler<PropertyChangedEventArgs> naming convention. So, if you do not know the type of the handler, you cannot declare it, and then things start to get messy. This messy stuff is implemented in the DynamicEventListener and allows you to simply subscribe to any event, regardless of the type. Not a lot of people will use this feature, but we hate to make things internal and disappoint the few that actually need the feature.

4) The DoubleClickToCommand works with bindings, but sometimes you want to create a view in the code-behind instead of in xaml (think of very dynamic views). In that case, you can now also inject an Action instance that has to be executed on double-click.

5) To set the focus on a UI element, one must write code in the code-behind. With the Focus behavior, you can define in xaml what control should get the focus (with delays, events, property changes, etc). 

For more information, see this blog post or this documentation.

 

A last tip: for all behaviors, there is an example application (both in WPF and Silverlight) demonstrating the behaviors. It can be found at http://catelexamples.codeplex.com

Dec 9, 2011 at 3:10 PM

Thanks, Geert.  I wasn't aware of your blog - that is a great resource. 

The only one I am still confused on is #1- ViewModelPropertyChanged.  If I understand correctly, I should be able to subscribe to this event in the code behind of a DataWindow, and then anytime the ViewModel for that window has a property that changes, the event handler should be called.  Is that right?  Does this happen automatically?  Because for me it is not happening. 

I just switched to using Catel 2.4 in my WPF app from Catel 2.3.  After changing the references, I got an error for each of my DataWindows complaining that they didn't implement the IViewModelContainer.ViewModelPropertyChanged event.  So, I added this event to each window's code behind.  So far so good.  However, if I subscribe to this event in the constructor of the window like so:

 

        public MyWindow()
        {
            InitializeComponent();

            this.ViewModelPropertyChanged += new EventHandler<PropertyChangedEventArgs>(MyWindow_ViewModelPropertyChanged);
        }

        void MyWindow_ViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
             //handler logic
        }

The handler never gets called.  What am I missing?

Tom

Dec 10, 2011 at 4:18 PM

What template did you use for the window? Logic in behavior or logic in view base? We always recommend logic in behavior, unless you have custom base windows. But even then, we recommend to create a custom base class that handles the creation of the behavior.

The ViewModelPropertyChanged is only fired automatically if the logic in view base is used. If you use the behavior, you have to chain the Behavior.ViewModelPropertyChanged to your custom ViewModelPropertyChanged yourself (that's why you create a custom window, to *not* use all the convenience features of the DataWindow).

Dec 11, 2011 at 3:35 PM

Hi Geert,

Thanks for your continued patience on this, but I am still a bit confused.  I am  using logic in behavior, and after your explanation above, I see why my window wasn't automatically raising ViewModelPropertyChanged.  It makes sense that this occurs in the behavior and that I need to capture that event in my window logic and raise the window's ViewModelPropertyChanged event in response.  I now have this working, but I have two questions:

1- You state above, "We always recommend logic in behavior, unless you have custom base windows. But even then, we recommend to create a custom base class that handles the creation of the behavior."  Did you mean to say that you always recommend logic in view base?  It seems to me that custom base windows is the one case where you would need logic in behavior.   Logic in view base seems to be the preferred method since it automatically raises the IViewModelContainer events on the window.

2-  My first thought on how to chain the Behavior.ViewModelPropertyChanged event to my window's ViewModelPropertyChanged event is to just modify the declaration of the mvvmBehavior in the xaml like so:

    <i:Interaction.Behaviors>
        <catel:WindowBehavior x:Name="mvvmBehavior"
                              ViewModelType="vm:MyWindowViewModel"
                              ViewModelPropertyChanged="OnViewModelPropertyChanged"/>
    </i:Interaction.Behaviors>

However, this didn't work - Intellisense didn't recognize ViewModelPropertyChanged, and compiling threw an error that the event doesn't exist.  Looking at the source code for Catel, I realized that ViewModelPropertyChanged is declared in MVVMBehaviorBase<TAttachedType, TLogicType>, but it is declared as a delegate, not an event (the "event" keyword is not used).  Same goes for ViewModelChanged.  Is this intentional?  If so, why?  I wound up chaining the two by adding the following in the constructor of the window (after InitializeComponent)

mvvmBehavior.ViewModelPropertyChanged += new EventHandler<PropertyChangedEventArgs>( (s, e) => RaiseViewModelPropertyChanged(e));

This works, but I am curious why you don't use the "event" keyword for ViewModelChanged and ViewModelPropertyChanged.

And finally, it seems this whole issue should be discussed in the documentation.  It is a pretty important issue to understand when using logic in behavior instead of logic in view base.

 

 

 

Dec 11, 2011 at 4:15 PM

1) For a correct implementation of 3rd party windows, see this documentation. It shows exactly what I mean.

2) See 1

The behaviors are disscussed here, and each behavior contains a text why you should or (would) use a behavior instead of a base class.

Dec 12, 2011 at 2:06 AM

Thanks for the reply, Geert.  I saw the documentation page you reference above about the behaviors and when to use them, but that page makes no mention of the fact that when using logic in behavior, you need to deal with the events yourself. 

Mostly out of curiosity, I am still interested in knowing why you didn't use the "event" keyword for the ViewModelChanged and ViewModelPropertyChanged events.  Is there some advantage to this?

Dec 12, 2011 at 6:46 PM

There is no advantage about that. It should have been events, so I changed that :)

Thanks for letting us know.

Dec 12, 2011 at 7:09 PM

Great - thanks, Geert.