Multiple ApplicationBars in WP7

Dec 12, 2010 at 7:51 AM

I am trying to mimic the behavior of the ApplicationBar that WP7 uses for it's mail client. By default you have a number of app bar icons for new, select, folders, etc but once you go into selection mode the app bar icons change to have a delete and move (there are some menu items) but you get the gist.

This is fairly easy to achieve by having 2 application bars as resources and switching between them. 

        <shell:ApplicationBar x:Key="defaultAppBar" IsVisible="True" IsMenuEnabled="True">
            <shell:ApplicationBar.MenuItems>
                <cal:AppBarMenuItem Text="favorites" Message="ShowFavorites" />
                <cal:AppBarMenuItem Text="settings" Message="ShowSettings"/>
            </shell:ApplicationBar.MenuItems>
            <cal:AppBarButton IconUri="/icons/appbar.add.rest.png" Text="new folder" Message="AddNewFolder"/>
            <cal:AppBarButton IconUri="/icons/appbar.refresh.rest.png" Text="refresh" Message="RefreshCurrentFolder"/>
            <cal:AppBarButton IconUri="/icons/appbar.feature.camera.rest.png" Text="upload photo" Message="UploadPhoto"/>
        </shell:ApplicationBar>
        
        <shell:ApplicationBar x:Key="editAppBar" IsVisible="True" IsMenuEnabled="False">
            <cal:AppBarButton IconUri="/icons/appbar.add.rest.png" Text="new folder" Message="AddNewFolder"/>
            <cal:AppBarButton IconUri="/icons/appbar.delete.rest.png" Text="delete items" Message="DeleteSelectedItems"/>
            <cal:AppBarButton IconUri="/icons/appbar.move.rest.png" Text="move items" Message="MoveSelectedItems"/>
        </shell:ApplicationBar>
ApplicationBar = (Microsoft.Phone.Shell.ApplicationBar)( inEditMode ? Resources["editAppBar"] : Resources["defaultAppBar"] );

The problem I am finding is that when I switch application bars, the messages are not being handled by Caliburn.  I have tried making the ViewModelBinder BindAppBar method public, which hooks up the action messages, but when they are fired, there is no context.

Any thoughts on how I might achieve this? Is there a simple way to call the methods on the ViewModel from the View, as I could do it from the view side?

Dec 12, 2010 at 8:02 AM

I am not sure if this is the best way, but atleast it is now calling my method.  I haved changed the ViewModelBinder.BindAppBar to be public, and I have had to change the ActionMessage.Invoke to create the conext if it was null.

        protected override void Invoke(object eventArgs) {
            Log.Info("Invoking {0}.", this);

            if(null == context || context.Target == null || context.View == null) {
                if( null == context )
                {
                    context = new ActionExecutionContext{ Message = this, Source = AssociatedObject };
                }
                PrepareContext(context);
                if (context.Target == null)
                {
                    var ex = new Exception(string.Format("No target found for method {0}.", context.Message.MethodName));
                    Log.Error(ex);
                    throw ex;
                }
                if (!UpdateAvailabilityCore())
                    return;
            }

            if (context.Method == null)
            {
                var ex = new Exception(string.Format("Method {0} not found on target of type {1}.",
                    context.Message.MethodName, context.Target.GetType()));
                Log.Error(ex);
                throw ex;
            }

            context.EventArgs = eventArgs;
            InvokeAction(context);
        }
So from my view I do this:
                inEditMode = value;
                ApplicationBar = (Microsoft.Phone.Shell.ApplicationBar)( inEditMode ? Resources["editAppBar"] : Resources["defaultAppBar"] );
                ViewModelBinder.BindAppBar( this );

Thoughts?
Apr 12, 2011 at 11:15 PM

Hi,

I just came across to this situation and your solution helped me a lot. With the latest source code I just need to make ViewModel.BindAppBar to public and that's all. It  just work.

It would be nice to have this fix in the next build or better way to achieve this.

 

Thanks,

Binoy

Apr 12, 2011 at 11:36 PM

Yes, that is basically what I have done, with the exception that I keep track of if I have already bound the bar already (note my defaultAppBar was bound already.

It might be better tracking this info in a dictionary also, if you need more than 2 app bars.

ApplicationBar = (Microsoft.Phone.Shell.ApplicationBar)( inEditMode ? Resources["editAppBar"] : Resources["defaultAppBar"] );
if( !appBarRebound )
{
    appBarRebound = true;
    ViewModelBinder.BindAppBar( this );
}