UpdateAvailability from the VM

Jan 8, 2011 at 6:44 AM
Edited Jan 8, 2011 at 8:25 AM

I am writing a WP7 application and wanted an application bar button to indicate the state of an item object, i.e if the item was not a favourite then using the button the user can add it to their favourites list but if it already is then disable the button.  I implemented the method and its associated guard like below.

        public void AddToFavourites()
        {
            if (_item != null)
            {
                _item.IsFavourite = true;
            }
        }

        public bool CanAddToFavourites()
        {
            return (_item != null) && (_item.IsFavourite == false);
        }

When the page loaded if the item was a favourite then it displayed correctly.  My problem however was that when i clicked the button I wanted the framework to do its stuff and update the button but unfortunately this doesnt happen automatically.  After much searching I found the necessary code within a method called UpdateAvailability in the ActionMessage class but was at a loss how to call it from the VM.  So I put the code on the back burner until I ran into Coroutines and by chance saw that the supplied context had exactly what I wanted.  The ActionExecutionContext has the message associated with my action so all i need to do is call UpdateAvailability on that message.  I implemented an appropriate IResult.

    public class UpdateAvailability : IResult
    {
        #region Implementation of IResult

        public void Execute(ActionExecutionContext context)
        {
            if (context != null && context.Message != null)
            {
                context.Message.UpdateAvailability();
            }
            Completed(this, new ResultCompletionEventArgs());
        }

        public event EventHandler<ResultCompletionEventArgs> Completed = delegate { };

        #endregion
    }

And now my method returns the IResult and the update gets called automatically.

        public IResult AddToFavourites()
        {
            if (_item != null)
            {
                _item.IsFavourite = true;
            }

            return new UpdateAvailability();
        }

This is a very neat solution and I was very happy but then I ran into the action filters and was able to simplify the solution even more.  The action filter implemented below does the same update after the action method has been called.

    public class UpdateAvailabilityAttribute : ExecutionWrapperBase 
    {
        protected override void AfterExecute(ActionExecutionContext context)
        {
            if (context != null && context.Message != null)
            {
                context.Message.UpdateAvailability();
            }
        }
    }

So the final code looks as follows which to me is very clean.

        [UpdateAvailability]
        public void AddToFavourites()
        {
            if (_item != null)
            {
                _item.IsFavourite = true;
            }

}

 

 

 

 

 

        
 
Coordinator
Jan 8, 2011 at 1:22 PM

Very cool. Briefly, here's an explanation of the difference between method and property guards. Method guards, as you have used, are only evaluated when parameter inputs change. Since your method doesn't have any parameters, it is never re-evaluated automatically. Also, WP7 parameter support is not fully functional due to unimplemented features in the SL runtime. Using filters or an IResult is a nice way to solve the problem. Another way would be to use a property guard. By using a property guard, you can trigger the re-evaluation of the condition by simply raising a property change notification. That's the standard way I handle this type of scenario.