Show view with ribbon button

Topics: UI Architecture
Oct 31, 2011 at 6:31 PM

Hello,

 

I have a question about showing a viewmodel after clicking a button on a ribbon.

 

I am designing an MDI application with a tabcontrol and a ribbon.

I have a shellviewmodel which consists of a ribbon and a tabcontrol. In the tabcontrol workspaces will be showed, the user can show a particular workspace by pressing the corresponding button on the ribbon.

 

All workspaces will be discovered at runtime, so that I can expand the application in the future. All workspaces will register there corresponding buttondata by the shell.

An example of the code for a button is shown below, this code will attach the click event of the button to a method “DisplayWorkspace” in the shellviewmodel.

ButtonData addButton = new ButtonData()
{
    Label = "Add Customer",
    LargeImage = new Uri("/App;component/Shell/Resources/Images/customer-icon_32x32.png", UriKind.Relative),

    KeyTip = "Add Customer",
    ToolTipTitle = "Add Customer",
    ToolTipDescription = "Add Customer to the database.",
    ToolTipFooterTitle = helpString,
    Message = "[Event Click] = [Action DisplayWorkspace($executioncontext)]",
    ToolTipFooterImage = smallHelpImage
};

 

My problem is, how can the DisplayWorkspace method determine which workspace needs to be shown?

The $executionContext value does not deliver the right information to the shellviewmodel so that it can determine the particular workspace.

 

Can somebody give me some hints on how to solve this.

 

Marcel

Nov 2, 2011 at 10:45 AM

I did something like this in my app, and I solved this problem using a XAML style, and with a tweak of the ButtonData class:

<!-- RibbonButton -->
    <DataTemplate DataType="{x:Type data:ButtonData}">
        <r:RibbonButton />
    </DataTemplate>
    <Style TargetType="{x:Type r:RibbonButton}" BasedOn="{StaticResource RibbonControlStyle}">
        <Setter Property="cal:Action.TargetWithoutContext" Value="{Binding Target}" />
        <Setter Property="cal:Message.Attach" Value="{Binding Message}" />
    </Style>

public class ButtonData : ControlData
{
    private readonly object target;
    private readonly string message = "[Event {0}] = [Action {1}]";

    public ButtonData(string label, Expression<Func<IEnumerable<IResult>>> messageTarget, object target)
    {
        this.target = target;

        var lambda = (LambdaExpression)messageTarget;
        MethodCallExpression methodCall = (MethodCallExpression) lambda.Body;

        message = string.Format(message, EventName, methodCall.Method.Name);

        Label = label;
    }

    public ButtonData(string label, Expression<System.Action> messageTarget, object target)
    {
        this.target = target;

        var lambda = (LambdaExpression)messageTarget;
        MethodCallExpression methodCall = (MethodCallExpression)lambda.Body;

        message = string.Format(message, EventName, methodCall.Method.Name);

        Label = label;
    }

    public ButtonData(string label, string actionName, object target = null)
    {
        this.target = target;

        message = string.Format(message, EventName, actionName);

        Label = label;
    }

    public virtual string EventName { get { return "Click"; } }

    public string Message { get { return message; } }
    public object Target { get { return target;  } }
}

The various constructor overloads allow you to specify the target method to be called either using a string, or a lamba expression. And this is this method which is responsible of opening the new view inside the tabcontrol:

new ButtonData("Teams", () => DisplayTeamsManagementView(), this),

public IEnumerable<IResult> DisplayTeamsManagementView()
{
    yield return Show.Child<TeamsManagementViewModel>();
}
Hope this helps

Nov 3, 2011 at 7:08 PM

It works perfect!

Thanks Zoubi.