This is a migrated thread and some comments may be shown as answers.

OnButtonClick Doesn't Update After LoadXml

1 Answer 24 Views
RibbonBar
This is a migrated thread and some comments may be shown as answers.
Mike
Top achievements
Rank 1
Mike asked on 22 Jul 2011, 05:02 PM
I have a project where I need to have a dynamic ribbon, that is, a ribbon that shows completely different items based on context.  The way I accomplish this is through the LoadXml method on the ribbon.  This works, but there are two side-effects.  One is that the OnButtonClick event returns whatever button was in that position originally, regardless of what's there now, and sometimes there is a jscript index out of bounds error, probably for the same reason.

The version of RadControls is 2011.2.712.40.
The OS is Win7 Ent, SP1.
The browser is IE9 (9.0.8112.16421).
Preferred language is C#.


There's a good amount of code.  I'll include what I think you'll need to repro.  I see the "Attach Your Files" link at the bottom, but the forum instructions say that you don't support attachments.

Here's Default.aspx:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="Default" %>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
<head id="Head1" runat="server">
    <title></title>
    <telerik:RadStyleSheetManager id="RadStyleSheetManager1" runat="server" />
</head>
<body>
    <form id="form1" runat="server">
    <telerik:RadScriptManager ID="RadScriptManager1" runat="server">
        <Scripts>
            <%--Needed for JavaScript IntelliSense in VS2010--%>
            <asp:ScriptReference Assembly="Telerik.Web.UI" Name="Telerik.Web.UI.Common.Core.js" />
            <asp:ScriptReference Assembly="Telerik.Web.UI" Name="Telerik.Web.UI.Common.jQuery.js" />
            <asp:ScriptReference Assembly="Telerik.Web.UI" Name="Telerik.Web.UI.Common.jQueryInclude.js" />
        </Scripts>
    </telerik:RadScriptManager>
    <script type="text/javascript">
        //Put your JavaScript code here.
    </script>
    <telerik:RadAjaxManager ID="RadAjaxManager1" runat="server" />
    <telerik:RadSkinManager ID="RadSkinManager1" Runat="server" Skin="Office2007" />
    <telerik:RadAjaxPanel runat="server" ID="RibbonPanel">
    <telerik:RadRibbonBar runat="server" ID="Ribbon" SelectedTabIndex="0" OnButtonClick="RibbonButtonClick">
        <telerik:RibbonBarTab Text="Project">
            <telerik:RibbonBarGroup Text="Project">
                <Items>
                    <telerik:RibbonBarButton Text="Settings" Size="Large" Value="PROJECT_SETTINGS" />
                    <telerik:RibbonBarButton Text="Closeout Assumptions" Size="Large" Value="CLOSEOUT_ASSUMPTIONS" />
                    <telerik:RibbonBarButton Text="View Solution" Size="Large" Value="CLOSEOUT_SOLUTION" />
                </Items>
            </telerik:RibbonBarGroup>
            <telerik:RibbonBarGroup Text="Actions">
                <Items>
                    <telerik:RibbonBarButton Text="Duplicate Project" Size="Large" Value="PROJECT_DUPLICATE" />
                </Items>
            </telerik:RibbonBarGroup>
            <telerik:RibbonBarGroup Text="Navigation">
                <Items>
                    <telerik:RibbonBarButton Text="Portfolio" Size="Large" Value="PORTFOLIO_LIST" />
                </Items>
            </telerik:RibbonBarGroup>
        </telerik:RibbonBarTab>
    </telerik:RadRibbonBar>
    </telerik:RadAjaxPanel>
    </form>
</body>
</html>

Here's Default.aspx.cs:
using System;
using System.Collections.Generic;
using System.Linq;
 
using Tel = Telerik.Web.UI;
 
public partial class Default : System.Web.UI.Page
    {
    protected void Page_Load(object sender, EventArgs e)
        {
        }
    protected void RibbonButtonClick(object sender, Tel.RibbonBarButtonClickEventArgs e)
        {
        string message = string.Format("Button {0} was clicked.", e.Button.Text);
        string details = string.Format("Group: {0}, Index: {1}", e.Group.Text, e.Index);
 
        SlimCommand command = _slimCommands.Where(item => item.Key == e.Button.Value).First();
        Ribbon.LoadXml(command.Ribbon);
        //ContentPanel.Attributes.Add("src", Page.MapPath(command.Destination));
        }
    protected static SlimCommand[] _slimCommands =
        {
            new SlimCommand("PORTFOLIO_LIST", "~/View/ListView.aspx", Ribbons.HomeMenu),
            new SlimCommand("PORTFOLIO_DASHBOARD","~/View/Dashboard.aspx", Ribbons.HomeMenu),
            new SlimCommand("PORTFOLIO_BENCHMARK","~/View/Benchmark.aspx", Ribbons.HomeMenu),
            new SlimCommand("PROJECT_NEW", "~/View/ListView.aspx", Ribbons.HomeMenu),
            new SlimCommand("PROJECT_DELETE", "~/View/ListView.aspx", Ribbons.HomeMenu),
            new SlimCommand("PROJECT_EDIT", "~/View/Project.aspx", Ribbons.ProjectMenu),
            new SlimCommand("PROJECT_SETTINGS", "~/View/Settings.aspx", Ribbons.ProjectMenu),
            new SlimCommand("PROJECT_DUPLICATE", "~/View/ListView.aspx", Ribbons.HomeMenu),
            new SlimCommand("CLOSEOUT_ASSUMPTIONS", "~/View/CloseoutAssumptions.aspx", Ribbons.ProjectMenu),
            new SlimCommand("CLOSEOUT_SOLUTION", "~/View/ViewSolution.aspx", Ribbons.ProjectMenu),
        };
    protected class SlimCommand
        {
        public SlimCommand(string key, string destination, string ribbon)
            {
            this.Key = key;
            this.Destination = destination;
            this.Ribbon = ribbon;
            }
        public string Key { get; private set; }
        public string Destination { get; private set; }
        public string Ribbon { get; private set; }
        }
    }
public enum SlimCommandId
    {
    PORTFOLIO_LIST,
    PORTFOLIO_DASHBOARD,
    PORTFOLIO_BENCHMARK,
    PROJECT_DUPLICATE,
    PROJECT_NEW,
    PROJECT_DELETE,
    PROJECT_EDIT,
    PROJECT_SETTINGS,
    CLOSEOUT_ASSUMPTIONS,
    CLOSEOUT_SOLUTION,
    };


Here's Ribbons.cs
/// <summary>
/// Summary description for Ribbons
/// </summary>
public static class Ribbons
    {
    public const string HomeMenu =
@"<?xml version='1.0' encoding='utf-16'?>
    <RibbonBar EnableAjaxSkinRendering='False'>
    <Tab Text='Portfolio'>
    <Group Text='View'>
      <Button Size='Large' Text='List' Value='PORTFOLIO_LIST' />
      <Button Size='Large' Text='Dashboard' Value='PORTFOLIO_DASHBOARD' />
      <Button Size='Large' Text='Benchmark' Value='PORTFOLIO_BENCHMARK' />
    </Group>
    <Group Text='Project'>
      <Button Size='Large' Text='Create New' Value='PROJECT_NEW' />
      <Button Size='Large' Text='Delete' Value='PROJECT_DELETE' />
      <Button Size='Large' Text='Edit' Value='PROJECT_EDIT' />
      <Button Size='Large' Text='Duplicate' Value='PROJECT_DUPLICATE' />
    </Group>
  </Tab>
</RibbonBar>";
 
    public const string ProjectMenu =
@"<?xml version='1.0' encoding='utf-16'?>
<RibbonBar EnableAjaxSkinRendering='False'>
  <Tab Text='Project'>
    <Group Text='Project'>
      <Button Size='Large' Text='Settings' Value='PROJECT_SETTINGS' />
      <Button Size='Large' Text='Closeout Assumptions' Value='CLOSEOUT_ASSUMPTIONS' />
      <Button Size='Large' Text='View Solution' Value='CLOSEOUT_SOLUTION' />
    </Group>
    <Group Text='Actions'>
      <Button Size='Large' Text='Duplicate Project' Value='PROJECT_DUPLICATE' />
    </Group>
    <Group Text='Navigation'>
      <Button Size='Large' Text='Portfolio' Value='PORTFOLIO_LIST' />
    </Group>
  </Tab>
</RibbonBar>";
    }

Given this, what's the normal way to accomplish dynamic ribbons?

Jamie

1 Answer, 1 is accepted

Sort by
0
Simon
Telerik team
answered on 28 Jul 2011, 01:29 PM
Hi Jamie,

The incorrect behavior and the 'index out of range' errors are caused by the fact that the RibbonBar structure is not stored in ViewState. This means that on each Page.Init event the RibbonBar is recreated from the markup or if the developer has added code for dynamic creation *in* the OnInit event handler of the page, from that code.

In your case, the LoadXml method is called later in the page life cycle, after the RB has been recreated from the markup. So, when you change the layout and click a button, when the ButtonClick event is about the fire, the initial structure (that in the markup) is present and the wrong click event fires. The IOOR error raises when a button at the end of the second structure is clicked, on which index a button does not exist in the original structure.

We have not yet found the proper solution to this problem. Storing everything in ViewState may be unexpected for some users because the RB is not a 'data-bound control'.

In your case, I suggest you implement the following approach. Every time you load the RB structure from XML on a postback event (e.g. ButtonClick) store (in a ViewState property, in Session, etc.), which XML has been loaded. Then in the OnInit event of the page load the previously loaded XML to make sure the structure matches that, which has been rendered. In this way, all the problems will be gone.

I hope this information helps. If you have additional questions, please let me know.

Greetings,
Simon
the Telerik team

Browse the vast support resources we have to jump start your development with RadControls for ASP.NET AJAX. See how to integrate our AJAX controls seamlessly in SharePoint 2007/2010 visiting our common SharePoint portal.

Tags
RibbonBar
Asked by
Mike
Top achievements
Rank 1
Answers by
Simon
Telerik team
Share this question
or