Message.Attach question

Feb 18, 2011 at 1:03 AM
Here's an example of a button which works at expected and responds to the state of CanInstall 
and Fires an Install method on the view model

<Button x:Name="Install" Content="Install" Margin="4"/>
But I want to be able to show a message to the user as the mouse moves over the button 
so I add a Message.Attach to intercept the MouseEnter event:

<Button x:Name="Install" Grid.Column="0" Content="Install" Margin="4" 
cal:Message.Attach="[Event MouseEnter] = [Action MouseEnter($source)]"

The message now appears but I notice that the button no longer calls the Install method and 
the button enabled state is no longer controlled by the CanInstall propery.  To restore
functionality I have do this:
<Button x:Name="Install" Grid.Column="0" Content="Install" Margin="4" IsEnabled="{Binding CanInstall}" 
cal:Message.Attach="[Event MouseEnter] = [Action MouseEnter($source)];[Event Click] = [Action Install()]"
Which is OK but I'm concerned I'm missing a trick.  Is there something I've missed or is this a consequence of
the ConventionManager not adding triggers once it finds one already attached to an element?
Feb 18, 2011 at 2:08 AM

You are correct. If you explicitly add actions to an element, we don't wire the convention. That's to prevent us from overwriting your explicit actions.

Feb 18, 2011 at 7:47 AM

@Rob in the above solution, wouldn't the binding over IsEnabled be ignored due to the availability update logic?

I encountered an issue yesterday where attaching a message to a Button would not allow me to bind the IsEnabled property freely.

Am I correct? If so, would it be possible to change the default implementation to avoid to change the IsEnabled value directly, in case a binding is already in place?

Feb 18, 2011 at 8:57 AM


The final example in the post is the live one.  The other two were manufactured to provide some background for the question.  So in my case I can confirm that binding IsEnable to the CanInstall view model property does work.

Feb 18, 2011 at 9:04 AM
Edited Feb 18, 2011 at 9:05 AM

@bseddon: I am sure that the above code works flawlessy. The fact is that you probably don't have a CanMouseEnter property, so you cannot notice the issue.

As long as CanInstall is the only availability guard, the code above works as expected because the binding matches the CM default behaviour. Unfortunally, if you inspect your visual tree at run-time, you'll notice that the binding over CanInstall is not there (CM availability check forces the local value to true or false depending on CanInstall value).

If you had a CanMouseEnter guard, returning always false for example, I suppose that the control would stay always disabled.

Feb 18, 2011 at 9:18 AM


If I create the CanMouseEnter property I don't see a problem with the enabled state of the button.  Instead the MouseEnter event handler is then never fired so the user message about the button is never displayed (whether CanMouseEnter returns true or false).

Feb 18, 2011 at 11:22 AM

Using the following view-model

#region Namespaces

using System.Windows;
using Caliburn.Micro;


namespace CaliburnMicroApplication1.ViewModels
    public class ShellViewModel : Screen
        private int counter;
        private string message;

        public ShellViewModel()
            Message = string.Empty;

        public string Message
            get { return message; }
                if (message != value)
                    message = value;

        public bool CanInstall
            get { return true; }

        public bool CanMouseEnter
            get { return false; }

        public void Install()

        public void MouseEnter(object source)
            Message = "Source: " + source + " [" + counter + "]";

associated to this view

<Window x:Class="CaliburnMicroApplication1.Views.ShellView"
        Title="MainWindow" Height="350" Width="525">
        <TextBlock x:Name="Message" DockPanel.Dock="Top"/>
        <Button Content="Test button"
                cm:Message.Attach="[Event MouseEnter] = [Action MouseEnter($source)];[Event Click] = [Action Install()]"
                IsEnabled="{Binding CanInstall}"/>

in my case the MouseEnter method gets called even if the CanMouseEnter guard is always false. And the enabling of the button is always true, as stated by CanInstall.

If you invert the order of the messages definition

<Button Content="Test button"
        cm:Message.Attach="[Event Click] = [Action Install()];[Event MouseEnter] = [Action MouseEnter($source)]"
        IsEnabled="{Binding CanInstall}"/>

the button stays disabled (in your case it works as expected because the binding is on the guard of the last message).

As I was saying the availability update removes the bining on CanInstall, and forces the enabling state to the availability of the last message attached.

The only thing I did not expect was MouseEnter to be called while it's guard is false... are you sure that in your case it is not called?

You can dounload the sample solution here.

Feb 18, 2011 at 1:34 PM


So, before we add the guard condition, we should check to see if there is already a binding present on the IsEnabled property. And if so, not apply the guard. Is that correct?

Feb 18, 2011 at 1:39 PM

@Rob Yes, I think it would be better this way.

Moreover, can you check why in the above sample the CanMouseEnter is not evaluated correctly? Is it a bug in CM or in the sample?

Feb 18, 2011 at 2:26 PM

Ok. I fixed the binding overwrite problem in 1a568a15b9da
I'll look inot the other issue next...

Feb 18, 2011 at 2:37 PM

Ok. The other issue is really as a result of the conflict of the two guards for the different actions (last one wins) and the explicit IsEnabled binding (which as of my last commit overrides everything).

So, I'm not going to make any changes related to that...otherwise things would get very complicated...

Feb 18, 2011 at 2:42 PM

Thanks Rob, just to clear things up: if I have two or more ActionMessages attached to a control, the last guard will be used for both execution and availability update, am I correct?

Feb 18, 2011 at 2:49 PM

Whatever the last ActionMessage you define's guard will control the UI availability.

Feb 18, 2011 at 2:59 PM

Yes, but what about the execution of the action? In the above example I defined 2 actions (in order) MouseEnter and Install. Two guards are defined, CanMouseEnter and CanInstall, the first being always false, the second always true.

As you confirmed, the UI is affected just by the last guard (so it is always enabled), but in the scenario MouseEnter action should not be executed, since its guard is always false... well, that's what I would expect. Am I wrong in thinking this?

Feb 18, 2011 at 3:00 PM

Hmm...I need to check on that. Back in a sec :)

Feb 18, 2011 at 3:04 PM

Actually, there is no explicit check before invocation. I could add this before incovation:

if (context.CanExecute != null && !context.CanExecute()) return;

Which wouldn't effect the UI, but would prevent individual actions from being invoked. Thoughts on that?

Feb 18, 2011 at 3:09 PM
Edited Feb 18, 2011 at 3:09 PM

(First of all thanks a ton Rob, today I am really trying to pissing you off with all these posts! :D)

It seems the proper behaviour to me (I consider the guard first a check on availability on the action, and as a side effect a way to deactivate the UI), but I hope this would not break existing code... the impact should be low (affected code should have 2 or more actions bound to the same control, everyone with its own guard), but I guess a typical 'BREAKING CHANGE' warning in the sources would be nice! :)

Feb 18, 2011 at 3:18 PM

This *might* have a performance implication in some cases. What if you had to turn on the explicit guard check (off by default) like this:

ActionMessage.EnforceGuardsDuringInvocation = true;

That would tell the framework to perform the extra check for all actions. Thoughts?

Feb 18, 2011 at 3:33 PM

I see your point, and I suppose this is a reasonable solution.

Feb 18, 2011 at 3:44 PM

In revision 82ac26b55d6d