November 2014

Sun Mon Tue Wed Thu Fri Sat
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30            










« Extracting XML data from drawings using a new .NET API in AutoCAD 2009 | Main | API overhaul for Autodesk Design Review »

April 09, 2008

The New RibbonBar API in AutoCAD 2009

Thank you to Sreekar Devatha, from DevTech India, for writing this article for the recently published ADN Platform Technologies Customization Newsletter. This article talks about the new Ribbon API referenced in this overview of the new APIs in AutoCAD 2009. A complete sample demonstrating the use of this API is provided as part of the ObjectARX 2009 SDK, under samples/dotNet/Ribbon.

Introduction

Most of the AutoCAD® UI was redesigned in this release. Ribbon, Menu browser and Tooltips are some of the prominent UI features to list. As you might already know the UI enhancements are based on the new Windows® Presentation Foundation (WPF) programming model introduced by Microsoft. So, let’s start with a small introduction to WPF and then we'll move on to the finer points of customizing the Ribbon bar.

What is WPF?

Windows Presentation Foundation (WPF) is a programming model introduced by Microsoft to build rich Windows client applications.

This graphical subsystem introduced in .NET Framework 3.0 provides a clear separation between appearance and behavior of applications. You generally use eXtensible Application Markup Language (XAML) to implement the appearance of an application while using managed programming languages (code-behind) to implement its behavior. XAML is the new XML-based UI definition language from Microsoft, and as such is a core part of WPF.

Without wasting too much time on WPF let us move quickly on to the Ribbon APIs. If you are new to WPF then you could go through the basics of WPF using the links below before starting with the Ribbon APIs.

Windows Presentation Foundation - MSDN

Windows Presentation Foundation - CodeProject

Microsoft WindowsClient.NET

AutoCAD Ribbon

Before diving into the Ribbon APIs it's necessary to understand the Ribbon layout and its terminology which are covered in this and the following section.

The AutoCAD Ribbon provides a single, compact placement for operations that are relevant to the current workspace. It overcomes the need to display multiple toolbars, reducing clutter in the application window. The Ribbon maximizes the area available for work using a single compact interface.

The Ribbon was built using WPF (part of .NET Framework 3.0) and a comprehensive set of APIs have been provided by Autodesk to help external developers customize it.

Ribbon Layout

The different components of the AutoCAD Ribbon are shown below. Also, depicted in the snapshot are the classes corresponding to each component.

Ribbon layout

Figure: the AutoCAD Ribbon and its layout

The Ribbon control is the top level control which contains everything in the Ribbon. It is composed of a series of panels, which are organized into tabs labeled by task.

Ribbon tabs control the display and order of Ribbon panels on the Ribbon. You add Ribbon tabs to a workspace to control which Ribbon tabs are displayed on the Ribbon. Ribbon tabs do not contain any commands or controls like a Ribbon panel does; instead, they manage the display of Ribbon panels on the Ribbon. Once a Ribbon tab is created, a panel can then be added to it. Ribbon tabs are of two types, standard and contextual. Standard tabs are always displayed while contextual tabs are displayed based on a particular context: for instance a Block Editor Tab is displayed while editing a Block.

Contextual tabs can appear in two modes:

Replace mode: In this mode the contextual tab gets added to the standard tabs as a regular tab. When the contextual tab is clicked it becomes active and the panels in the contextual tabs replace the panels in the previously active tab.

Append mode: In this mode contextual tabs form another tab set similar to the standard tab set and is displayed side-by-side with the standard tabs and panels. There are two tabs active any time and activating a tab in one tab set does not affect active tab in the other tab set.

Ribbon panels are organized by rows, sub-panels, and panel separators. Rows and sub-panels are used to organize how commands and controls are displayed on the Ribbon panel. A row, similar to a toolbar, determines the order and position that commands and controls appear on the Ribbon panel. Rows run horizontally on a Ribbon panel. If all the commands and controls cannot be displayed on the Ribbon panel, a gray down arrow is displayed for expanding the Ribbon panel. Rows can be divided using a sub-panel which, holds rows to order and position commands and controls. Commands and controls can be added to rows and sub-panels, you can remove the commands and controls that you use infrequently, and rearrange the order of commands and controls. Along with commands and controls, you can also create flyouts that contain multiple commands and only take up the space of a single command.

Prerequisites
Modules, Namespaces & Classes

The core UI framework for AutoCAD is present in AdWindows and AcRibbon contains the Ribbon specific implementation. These are managed UI class libraries developed using .NET 3.0 and WPF. Only .NET APIs are available and no C++ wrappers are provided.

AdWindows.dll

This library implements the framework for the following Autodesk UI features.

  • Ribbon classes
  • Autodesk controls
  • Tooltips
  • Menu browser
  • Task dialog, etc.

These are the Ribbon-specific classes under the Autodesk.Windows namespace of this DLL.

  • RibbonControl
  • RibbonTab
  • RibbonPanel
  • RibbonPanelSource
  • RibbonRow
  • RibbonItem
  • RibbonButton
  • RibbonDropDownButton
  • RibbonSeperator
  • RibbonForm
  • RibbonHwnd
  • RibbonRowPanel, etc.

For more details regarding these classes refer the ObjectARX® Managed Reference guide available in the ObjectARX 2009 SDK.

AcRibbon.dll

This library was actually meant to be an internal-only DLL except for the very few APIs which are  discussed in this article below. All other APIs included in the DLL should be considered as internal-only.

Classes

  • Palette that hosts the AutoCAD Ribbon control
    • Autodesk.AutoCAD.Ribbon.RibbonPaletteSet

  • AutoCAD Ribbon control
    • Autodesk.AutoCAD.Ribbon.RibbonServices. RibbonPaletteSet.RibbonControl

Properties

  • Property to access the default Ribbon host window which is a palette
    • Autodesk.AutoCAD.Ribbon.RibbonServices. RibbonPaletteSet

Note: You are advised not to use any of the internal APIs as they are unsupported and could be changed or dropped without prior notice.

Custom Ribbon Tab

As discussed above in the Ribbon Layout section, we need to create panels with Ribbon items placed on them. Then, these panels should be categorized based on their usage and hosted on your application-specific Ribbon tabs. To demonstrate this we'll now look into the finer points of the API by adding a simple button to a panel and then host the panel on a tab (Custom Tab).

Button

In this section we'll add a button to the ribbon bar. If we take a look at the classes listed above we have the RibbonButton class which can be used to create a button to be placed on the Ribbon. So, let’s start with the creation of a RibbonButton instance as below:

RibbonButton button = new RibbonButton();

button.Text = "Click Me";

// resourceDictionary

// A XAML resource dictionary that defines a ButtonImage

button.LargeImage =

  resourceDictionary["ButtonImage"] as BitmapImage;

button.Orientation = Orientation.Vertical;

button.Size = RibbonItemSize.Large;

button.ShowText = true;

button.ShowImage = true;

button.Id = "ClickMe_1";

Now, this button instance should be placed on a panel that can then be hosted by a tab. But before actually creating the panel we need a row in which to place the button, as discussed earlier.

// Create a Row to add the RibbonButton

RibbonRow row = new RibbonRow();

row.Items.Add(button);

// Create a Ribbon panel source in which to

// place ribbon items

RibbonPanelSource panelSource =

  new RibbonPanelSource();

panelSource.Title = "Custom Panel";

panelSource.Rows.Add(row);

// Create a panel for holding the panel

// source content

RibbonPanel panel = new RibbonPanel();

panel.Source = panelSource;

The panel should be hosted on the tab which in turn should be added to the Ribbon control and the equivalent code to achieve this is below:

// Create a tab to manage the above panel

RibbonTab tab = new RibbonTab();

tab.Title = "Custom Tab";

tab.Id = "CustomTab";

tab.IsContextualTab = false;

tab.Panels.Add(panel);

// Now add the tab to AutoCAD Ribbon bar...

RibbonControl ribbonControl =

  Autodesk.AutoCAD.Ribbon.RibbonServices.

    RibbonPaletteSet.RibbonControl;

ribbonControl.Tabs.Add(tab);

// ... and activate the tab

ribbonControl.ActiveTab = tab;

The below snapshot shows the button added to AutoCAD's Ribbon.

Custom ribbon panel inside AutoCAD 2009

Figure: the button added to the Ribbon bar

One more item that was missing in the above code was an event to identify the click of the button. The following code implements the click event.

button.Click += new RoutedEventHandler(button_Click);

private static void button_Click(

  object sender, RoutedEventArgs e)

{

  RibbonButton button = sender as RibbonButton;

  if (button != null && (button.Id == "ClickMe_1")

  {

    MessageBox.Show("Click Me clicked ", "Click Me");

    e.Handled = true;

  }

}

The above code might also be implemented using a combination of XAML and C# code-behind as shown below.

XAML that defines the RibbonTab

  <adw:RibbonTab

    x:Key="TabXaml" Title="Custom Tab XAML" Id="CustomTabXaml">

    <adw:RibbonPanel >

      <adw:RibbonPanelSource Title="Custom Panel XAML" >

        <!--Add a ribbon row-->

        <!--Note: You could add only rows

                  to the panel source content-->

        <adw:RibbonRow x:Uid="adw:RibbonRow_1">

          <!--Add Ribbon Items here-->

          <!--The items could be any RibbonItem derived classes-->

          <!--Like RibbonButton

              RibbonDropDownButton,

              RibbonForm,

              RibbonHwnd,

              RibbonLabel

              RibbonMenuButton,

              RibbonRowPanel,

              RibbonSeperator,

              RibbonToggleButton

              or any RibbonItem derived custom controls-->

          <adw:RibbonButton Id="ClickMe_2" ShowText="true">

            <adw:RibbonButton.Orientation>

              <Orientation>

                Vertical

              </Orientation>

            </adw:RibbonButton.Orientation>

            <adw:RibbonButton.Image>

              <BitmapImage

                UriSource="Images/bitmap1.bmp"/>

            </adw:RibbonButton.Image>

            <adw:RibbonButton.LargeImage>

              <BitmapImage

                UriSource="Images/bitmap1.bmp"/>

            </adw:RibbonButton.LargeImage>

            <adw:RibbonButton.Size>

              <adw:RibbonItemSize>

                Large

              </adw:RibbonItemSize>

            </adw:RibbonButton.Size>

            <adw:RibbonButton.Text>

              Click Me

            </adw:RibbonButton.Text>

            <adw:RibbonButton.ToolTip>

              <src:RibbonToolTip

                BasicText = "Click Me basic help"

                CommandName = "ClickMe"

                ExtendedURISource =

                  "/MyRibbon;component/Dictionary1.xaml"

                ExtendedURISourceKey = "ClickMe_ToolTip"

                HelpSource = "./Help/readme.chm"

                HelpTopic =

                  "WS1a9193826455f5ff1dbc298511635bea8752e2f"/>

            </adw:RibbonButton.ToolTip>

          </adw:RibbonButton>

        </adw:RibbonRow>

      </adw:RibbonPanelSource>

    </adw:RibbonPanel>

  </adw:RibbonTab>

C# code-behind to add a button to the ribbon bar using the tab defined in XAML

[CommandMethod("AddButtonXAML")]

public static void AddButtonXAML()

{

  // Create a RibbonTab using the resourceDictionary

  RibbonTab tab =

    resourceDictionary["TabXaml"] as RibbonTab;

  // Find the ribbon button and add the event

  RibbonRow row = tab.Panels[0].Source.Rows[0];

  RibbonItemCollection coll = row.Items;

  foreach (RibbonItem item in coll)

  {

    if (item is RibbonButton)

    {

      RibbonButton button = (RibbonButton)item;

      if (button.Id == "ClickMe_2")

      {

        button.Click +=

          new RoutedEventHandler(button_Click);

      }

    }

  }

  // Now add the tab to AutoCAD Ribbon bar and activate it

  ribbonControl.Tabs.Add(tab);

  ribbonControl.ActiveTab = tab;

}

ToolTip

The next thing you would want to do once you add your objects to the Ribbon bar is to display a tooltip for these objects.

The ToolTip property of the RibbonItem class accepts an object so, we could assign a control object to it to display the control’s content as a tooltip. In this example here we define a Grid control. The control intern uses the Autodesk.Windows.ProgressivePanel class to implement the extended tooltip feature that is available with the AutoCAD tooltips.

XAML

<Grid x:Key="ClickMe_ToolTip">

  <StackPanel>

    <!--Header Part-->

    <StackPanel Orientation="Horizontal" Margin="5,5,5,5">

      <TextBlock Text="ClickMe">

        <TextBlock.FontWeight>

          <FontWeight>

            Bold

          </FontWeight>

        </TextBlock.FontWeight>

      </TextBlock>

    </StackPanel>

    <!--Basic help information -->

    <StackPanel Margin="5,5,5,5">

      <TextBlock

        Text="This is basic help of click me command">

        <TextBlock.TextWrapping>

          <TextWrapping>

            Wrap

          </TextWrapping>

        </TextBlock.TextWrapping>

      </TextBlock>

    </StackPanel>

    <!--Extended help information -->

    <adw:ProgressivePanel Margin="5,5,5,5">

      <StackPanel/>

      <!--Click Me Extended Tooltip-->

      <Grid>

        <StackPanel Orientation="Vertical" Margin="0,0,0,0">

          <TextBlock>

            Click Me extended ToolTip

          </TextBlock>

          <Image Margin="40,10,0,0" 

            Width="150" Height="150" 

            Source="/MyRibbon;component/Images/Smiley.png" />

        </StackPanel>

      </Grid>

    </adw:ProgressivePanel>

    <!-- Footer Part -->

    <Line Stroke="Black" StrokeThickness="2" X2="250"/>

    <StackPanel Orientation="Horizontal" Margin="5,5,5,5">

      <Grid VerticalAlignment="Center"

            HorizontalAlignment="Left">

        <Grid.ColumnDefinitions>

          <ColumnDefinition Width="21" />

          <ColumnDefinition Width="179" />

        </Grid.ColumnDefinitions>

        <Image HorizontalAlignment="Left" Grid.Column="0"

              Width="16" Height="16">

          <Image.Source>

            /MyRibbon;component/Images/Help.gif

          </Image.Source>

        </Image>

        <TextBlock HorizontalAlignment="Left" Grid.Column="1"

                  FontWeight="Bold">

          Press F1 for more help

        </TextBlock>

      </Grid>

    </StackPanel>

  </StackPanel>

</Grid>

button.ToolTip = resourceDictionary["ClickMe_ToolTip"];

We can do away with this statement above if we define the button in the XAML file by adding the tooltip to RibbonButton in the XAML as below:

<adw:RibbonButton.ToolTip>

  <!-- Define tooltip here, above XAML without

      x:Key value could be used -->

</adw:RibbonButton.ToolTip>

Here's a snapshot of the extended tooltip:

Custom extended tooltip in AutoCAD 2009

Figure: Ribbon object tooltip

Although we can display tooltip using a control as done above, we will not be able to implement the F1 event-handling mechanism using this approach. The ToolTip UI controls like Autodesk.Windows.ToolTip or System.Windows.Controls.ToolTip with F1 event handlers will not help us here because the Ribbon bar does not accept them similar to the way we could not use the Button class to add a button to the Ribbon bar. This particular feature could easily run into an article in itself, so we'll stop at this point to continue in a future article.

TrackBack

TrackBack URL for this entry:
http://www.typepad.com/services/trackback/6a00d83452464869e200e551cc25cc8834

Listed below are links to weblogs that reference The New RibbonBar API in AutoCAD 2009:

blog comments powered by Disqus

Feed/Share

10 Random Posts