Using Ribbon with MVVM?

Apr 2, 2009 at 4:11 PM
I am developing a WPF application using MVVM and the current version of the Ribbon control. The commands in my app are all ICommands, which are exposed as properties of the main window's view model. I don't want to change that to accommodate the Ribbon, particularly since the RibbonCommand appears to be going away in the next release.

What I had hoped to do was bind a RibonCommand's Executed and CanExecute properties to my ICommand Execute() and CanExecute() methods, since I can't bind a RibbonCommand to an ICommand directly. Here is the code I tried:

<r:RibbonCommand x:Key="Open"
    CanExecute="{Binding Path=FileOpen.CanExecute}"
    Executed="{Binding Path=FileOpen.Execute}"
    LabelTitle="Open"
    LabelDescription="Opens an existing data file."
    LargeImageSource="Images/OpenLarge.png"
    SmallImageSource="Images/OpenSmall.png"
    ToolTipTitle="Open Data File"
    ToolTipDescription="Opens an existing data file." />

The compiler throws the following error: "Error 1 CanExecute="{Binding Path=FileOpen.CanExecute}" is not valid. '{Binding Path=FileOpen.CanExecute}' is not a valid event handler method name. Only instance methods on the generated or code-behind class are valid. "

Here's my question: Is there any way to do the binding that I am trying to do, or do I have to implement handlers in my code-behind that invoke my ICommand methods? Thanks for your help.

David Veeneman
Foresight Systems
May 22, 2009 at 6:36 AM

Hi. I'm in the same problem. I'm using Office 2007 Ribbon conrol in Model-View-ViewModel application. What I'm using now is custom class RibbonCommandReference derived from RibbonCommand. This class expose new simple property called Command which accepts CommandReference declared in XAML resources and redirect all calls to methods maped to CommandReferene instance. I don't know is this a good way to reach the exprected behavior. Today I'll try VS2010 Beta1 with .NET 4.0 Beta1 and I hope find some improvements there.

Best regards.

May 22, 2009 at 1:09 PM

I've created an own RibbonCommand:

public class RibbonCommandEx : RibbonCommand
    {
        private ICommand _delegatedCommand;
        public ICommand DelegatedCommand
        {
            get { return _delegatedCommand; }
            set
            {
                if (_delegatedCommand != value)
                {
                    _delegatedCommand = value;
                    if (_delegatedCommand != null)
                    {
                        this.CanExecute += RibbonCommandEx_CanExecute;
                        this.Executed += RibbonCommandEx_Executed;
                    }
                    else
                    {
                        this.CanExecute -= RibbonCommandEx_CanExecute;
                        this.Executed -= RibbonCommandEx_Executed;
                    }
                }
            }
        }

        private void RibbonCommandEx_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            DelegatedCommand.Execute(e.Parameter);
        }

        private void RibbonCommandEx_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = DelegatedCommand.CanExecute(e.Parameter);
        }
    }

<commands:CommandReference x:Key="WelcomePageCommandReference" Command="{Binding WelcomePageCommand}"/>

<commands:RibbonCommandEx x:Key="RibbonWelcomePageCommand"
                              DelegatedCommand="{StaticResource WelcomePageCommandReference}"
                              LabelTitle="{x:Static properties:Resources.RSTR_WelcomePage}"
                              LabelDescription="{x:Static properties:Resources.RSTR_WelcomePageDescription}"
                              SmallImageSource="/Resources/Images/WelcomePage.png"
                              LargeImageSource="/Resources/Images/WelcomePage.png"
                              ToolTipImageSource="/Resources/Images/WelcomePage.png"
                              ToolTipTitle="{x:Static properties:Resources.RSTR_WelcomePage}"                                         
                              ToolTipDescription="{x:Static properties:Resources.RSTR_WelcomePageDescription}"/>

May 22, 2009 at 10:25 PM

Thank you for your post and for comprehensive example. Appreciate highly your help to clarify this.

Sep 24, 2009 at 1:54 PM

Hi, sorry if I'm being stupid, but I just can't figure out what is the CommandReference.

Can someone give me a clue?

Tks

Diego

Sep 24, 2009 at 2:02 PM

Don't bother with the current version of the WPF Ribbon--it's a mess. Microsoft scrapped it, mainly because it wasn't compatible with MVVM, and they have rewritten it. It's supposed to be out any time now.

Sep 24, 2009 at 5:50 PM

I've found it.

Tks everyone.

Oct 14, 2009 at 4:35 AM

To clarify others, here is how to use above code. CommandReference class is created for you, when you create a new WPF Model-View Application. To have that project type you would need to install the MVVM template toolkit, which you can download here WPF Model-View-ViewModel Toolkit

<Window.Resources>

<commands:CommandReference x:Key="WelcomePageCommandReference" Command="{Binding WelcomePageCommand}"/>

<commands:RibbonCommandEx x:Key="RibbonWelcomePageCommand"
                              DelegatedCommand="{StaticResource WelcomePageCommandReference}"
                              LabelTitle="{x:Static properties:Resources.RSTR_WelcomePage}"
                              LabelDescription="{x:Static properties:Resources.RSTR_WelcomePageDescription}"
                              SmallImageSource="/Resources/Images/WelcomePage.png"
                              LargeImageSource="/Resources/Images/WelcomePage.png"
                              ToolTipImageSource="/Resources/Images/WelcomePage.png"
                              ToolTipTitle="{x:Static properties:Resources.RSTR_WelcomePage}"                                          
                              ToolTipDescription="{x:Static properties:Resources.RSTR_WelcomePageDescription}"/>

</Window.Resources>

.
.
.
 <r:Ribbon.ApplicationMenu>
       <r:RibbonApplicationMenu Command="{StaticResource RibbonWelcomePageCommand}">
                </r:RibbonApplicationMenu>
</r:Ribbon.ApplicationMenu>
<r:Ribbon.ApplicationMenu>

                <r:RibbonApplicationMenu Command="{StaticResource RibbonExitCommand}">
                    <r:RibbonApplicationMenuItem Command="{StaticResource RibbonExitCommand}">
                    </r:RibbonApplicationMenuItem>
                </r:RibbonApplicationMenu>
            </r:Ribbon.ApplicationMenu>

.
.

 

My 2 cents.

 

Oct 15, 2009 at 9:57 AM

Thanks for this. It has been very useful.

But!! I do have another question. How can I change the ribbontab Selected event to a Command in the viewmodel.

<r:RibbonTab Label="Home" Selected="RibbonTab_Selected"  >
<r:RibbonTab Label="House Keeping" Selected="RibbonTab_Selected">
<r:RibbonTab Label="Config" Selected="RibbonTab_Selected">

 
What I need to do is, each tab has its own workspace. Any button clicked on the selected tab goes only to the selected workspace. Selecting a different tab hides the previous workspace and shows this workspace only. The current code behind looks like this

private void RibbonTab_Selected(object sender, RoutedEventArgs e)
        {
            switch (ribbonmenu.SelectedTab.Label)
            {
                case "Home":
                    SelectControl(ucHome);
                    break;
                case "House Keeping":
                    SelectControl(ucHouse);
                    break;
                case "Config":
                    SelectControl(ucConfig);
                    break;
              default:
                    SelectControl(ucHome);
                    break;
            }

        }
private void SelectControl(Control selectedControl)
        {
            foreach (UserControl uc in workspace.Children.OfType<UserControl>())
            {
                uc.Visibility = Visibility.Collapsed;
            }

            selectedControl.Visibility = Visibility.Visible;
        }

 

Nov 19, 2009 at 8:33 PM

sergioesp, I am feeling a bit dense here :( .

I have copied the CommandReference.cs and Created the RibbonCommandEx class.

I have a global command class :

namespace Infrastructure
{
public static class MenuCommands
{ //Composite command from the Prism Framework public static CompositeCommand DivertCommand = new CompositeCommand();
}

And in my ViewModel, I have


         private DelegateCommand<object> divertCommand;
private void DivertItem(object e)
{
Debug.WriteLine("Itemwas diverted" );
}
public System.Windows.Input.ICommand DivertCommand
{
get { if (divertCommand == null)
{
divertCommand = new DelegateCommand<object>(DivertItem, delegate { return true; });
}
return divertCommand;
}
}

.....
in constructor

Infrastructure.MenuCommands.DivertCommand.RegisterCommand(DivertCommand);

and finally, in xaml...

<r:RibbonWindow.Resources>
	 <infrastructure:CommandReference x:Key="DivertCommandReference" Command="{Binding infrastructure:MenuCommands.DivertCommand}" />
	 <infrastructure:RibbonCommandEx x:Key="DivertCommand"
								   DelegatedCommand="{StaticResource DivertCommandReference}"
									LabelTitle="Divert"
								 ToolTipTitle="Divert Item"
								 ToolTipDescription="Divert a items"
								 SmallImageSource="images/Divert.png"
								 LargeImageSource="images/Divert.png"
							/>

	</r:RibbonWindow.Resources>
.

The RibbonEx hits the DelegatedCommand, but the commandReference never gets the OnCommandChanged(), which it does in a project from the MVVM toolkit.

Any idea what I am missing here ? Some syntax issue ? The visual is that the ribbonbutton is never CanExecute==true.
Larry
	
	 
	 

	

Nov 20, 2009 at 10:31 AM

Hi,

Your command call is wrong  - Command="{Binding infrastructure:MenuCommands.DivertCommand}"

This should be property in your ViewModel - Command="{Binding DivertCommand}"

The viewmodel looks like:

public class ViewModel
{
private SimpleCommand divertCommand;


public ViewModel()
{
testCommand = new SimpleCommand
        {
            CanExecuteDelegate = x => true,
            ExecuteDelegate = x => ExecuteCommand()
        };
}

        public SimpleCommand DivertCommand
        {
            get { return divertCommand; }
        }

        private void ExecuteCommand()
        {
            DivertCommand.CommandSucceeded = false;

//Your code to execute

            DivertCommand.CommandSucceeded = true;
        }
}

I use SimpleCommand commandreference as used by Sacha Barber http://www.codeproject.com/KB/WPF/Cinch.aspx

Nov 20, 2009 at 3:51 PM

Thanks Seventeeth !

 

It was in fact an issue with the syntax. I was able to use this with the CompositeCommand. This was important because several modules needed to "play" with the command, and the original VM didn't need the dependicies.

 
<infrastructure:CommandReference x:Key="DivertCommandReference" Command="{x:Static infrastructure:MenuCommands.DivertCommand}" />


Allows me to simply use the static command like I do with other things.
Dec 8, 2009 at 11:39 AM

Thank you all, I have found this discussion very helpful.

I have just started to get to grips with the ribbon control and MVVM and would like some help regarding how best to implement it into the MVVM pattern.

I take it you should have one main view containing the ribbon, that is binded to a main view model. From this main view I want to access a number of different child views, which will be displayed within the main view. The child views should use the same ribbon contained within the main view. How do I bind the ribbon controls so that depending on which child view is open the ribbon control responds to that view?

Jan 28, 2010 at 12:15 AM

segioesp!

You are a freaking legend. Well done, man.

I downloaded the MVVM toolkit, foudn the CommandReference class and converted it to VB.NET.

Now, with sergioesp's RibbonCommandEx I am using the RibbonCommand in a fully MVVM-complaint manner (including Input Gestures) with no forwarding of CanExecute and Execute handlers  from code-behind.

Thanks WPF Futures for the CodeReference class and thanks sergio for the RibbonCommandEx class

Will post the conversion to VB.NEt on my blog soon.

Jan 31, 2010 at 11:28 AM
baraholka wrote:

segioesp!

You are a freaking legend. Well done, man.

I downloaded the MVVM toolkit, foudn the CommandReference class and converted it to VB.NET.

Now, with sergioesp's RibbonCommandEx I am using the RibbonCommand in a fully MVVM-complaint manner (including Input Gestures) with no forwarding of CanExecute and Execute handlers  from code-behind.

Thanks WPF Futures for the CodeReference class and thanks sergio for the RibbonCommandEx class

Will post the conversion to VB.NEt on my blog soon.

Here's Sergio's Code in VB.NET with support for InputGestures and not requiring you to use WPF MVVM Toolkit http://waxtadpole.wordpress.com/2010/01/31/integrating-wpf-ribbon-with-prism-and-mvvm-with-vb-net-example/