Telerik blogs

by Francois Vanderseypen and Miroslav Miroslavov

» Full source code of the demo application here

The new RadDiagram framework brings, together with a host of new exciting things in Telerik's 2012 Q1 release, a new world of possibilities to the WPF and Silverlight community. This article attempts to show you that Telerik's RadDiagram is easy-to-use and that it differs from other Telerik controls in that it more closely represents a framework than a control. It’s an invitation to augment and customize the RadDiagram toolset in function of your application and business context. That said, we have to tell you straight away that RadDiagram, as released with Q1, is just the beginning. We have at this point put down the foundations for lots of exciting things to come and you can expect to see this RadDiagram branch off in various directions in coming releases. Great care and much energy were put in making it a flexible, robust, and broad framework for future developments. We have tried to make your (and our) task of customizing things easy while retaining the possibility to make the complex possible

The dashboard designer described in this article aims to highlight various development tasks related to RadDiagram and how to integrate it into a real-world LOB application. It also tries to underline the fact that the diagramming world is a very broad subject on many levels. In its most basic form a diagram (graph, network) is just a set of shapes and lines connecting these shapes, but diagramming frameworks are also used for a wild spectrum of other tasks:

  • For so-called  HMI (human-machine interface) diagrams where the shapes contain data from sensors and other real-time data providers
  • In geographic maps to position labels (using appropriate layout algorithms) and to calculate shortest paths or other extremum, graph-based things
  • To design workflows in which case shapes and connections are tightly bound to an underlying API
  • To simulate processes and represent data logic (so-called system dynamics) in which case the graph effectively represents a flow of data and logical switches. The typical example being the diagrams used in rendering applications where texture and material properties are modeled through graphs.
  • For data visualizations and data analysis; social networks and IP networks, for example

 

[Picture above] Typical dashboard in our sample application representing an overview of stock-related data coming from Yahoo Finance.

 

Yet another context wherein diagrams come in handy is when you need a flexible surface on which you need to drop elements to design a document or data dashboard. While graphs are intrinsically related to links and connections, nothing prevents you from using a diagram framework without them and thus reduce it to a layout or design engine (a form designer anyone?). Our financial dashboard designer uses the RadDiagram surface in both ways; to design data dashboards (no connections here) and to represent the hierarchical structure of these dashboards (relationship graph).

 

[Picture above] The very same RadDiagram surface which presents a digital dashboard is re-used to display the relationships contained within different dashboards by inspecting the hyperlinks between the screens.

 

How does the application gets its relational structure? Put simply, the hyperlinks you add on a dashboard can be internal; you can create a link which jumps to another dashboard page much like hyperlinks in a web site.

[Picture above] Example of an internal link in a dashboard page.

 

[Picture left]The link editor (which pops up on double-clicking a link) allows you to add an internal link to another dashboard page or to an arbitrary (external) address.

 

The important bit here is the fact that across the application there is only one RadDiagram instance used in multiple ways and that all the dynamics occur through the (de)serialization. In fact, the generic flow in the application is as follows:

  • At any moment there is only one active page which corresponds to a diagram. You can remove or add pages as you please, but only one is active at a time, much like a TabControl tab-page in fact.
  • From the toolbox data elements can be drag-dropped onto the diagram (dashboard) and real-time data is fetched from the Yahoo Finance service (you need to specify a stock symbol, of course).
  • The elements can be customized, if needed, by double-clicking them.
  • When a page is saved it's being serialized to the isolated storage space and the hyperlinks are analyzed thus creating a graph (an hypergraph in fact) of relations between pages/dashboards.
  • Whenever a page is loaded from the storage the corresponding diagram XML is deserialized.

 

A dashboard page in edit mode

[Picture above] A dashboard page in design mode shows some additional elements in the UI: the toolbox and the toolbar. Through these you can achieve a very diverse set of data pages. In addition, it’s really easy to add your own toolbox items.


This flow demonstrates the following aspects of RadDiagram:

  • The flexible serialization pipeline you can plug into to include your application-specific data.
  • The ease with which you can customize the RadDiagram toolbox to incorporate your own bits.
  • The way you can use the many switches and properties of the diagramming surface to model a particular behavior, enabling/disabling e.g. connections, resizing, rotation, and so on.
  • The speedy loading and unloading of diagrams, which effectively enables a multi-view paradigm, bypassing the need for a TabControl
  • The way you can use diagramming shapes as containers for other Telerik controls, for your own data or to act as recipients for real-time data sources

Now that you have an overview of what the demo application does and its various features let’s dig a bit more into the technical details.

A note on the Yahoo Finance API

The dashboard designer uses realtime financial information from the Yahoo Finance API:

  • You can drag-drop the 'company profile' shape onto the diagram surface and it will fetch the company profile for the stock symbol of your choice.
  • General financial information, timeline graph and other data can be fetched in the same way. Each type of information is presented in a different shape (format) and demonstrates how you can combine Telerik's controls into the RadDiagram framework
  • RSS news feeds can be appended

The code to access the Yahoo Finance API is quite straightforward and one can, of course, reuse these controls and the underlying code for other data sources.

 

Sample Yahoo Finance output in a custom shape

[Picture left] Sample output of the Yahoo API which lets you query the stock details of an arbitrary symbol (here show is ‘MSFT’).

Creating custom shapes with RadDiagram

The RadDiagram framework comes with a standard set of flowcharting shapes (geometry shapes) but this shouldn't prevent you from enlarging it with your own set. In fact, diagramming is such a vast domain and its integration within the business context is so tight that any diagramming framework would fail to deliver a complete set of shapes. Rather than trying to offer lots of shapes RadDiagram offers you a flexible and straightforward route to designing custom shapes and embedding (Telerik or third-party) controls.

RadGauge inside a RadDiagram shape

[Picture left] Sample custom RadDiagram shape hosting a RadChart control,which displays the latest trade price as well as the procentual change.

 

The generic recipe for creating a custom shape goes as follows:

  • Inherit from a base class, either RadDiagramShapeBase or RadDiagramShape. The latter one contains a Geometry property, if you need to have some geometry inside your shape.
  • Design a control or content template in XAML. This is the point where you can go wild in combining the Telerik controls and all the goodness of the XAML framework.
  • Optional: Add some (dependency) properties reflecting the business context. For example, in the custom shapes provided with the sample you’ll often see the stock Symbol property defined.
  • Optional: Override a couple of serialization methods, if the custom properties need to be saved/loaded/copied.

Let’s take, as an example, the GaugeShape from the sample, which (see adjacent picture) displays the latest price and price change of a stock. The shape inherits from RadDiagramShape

public sealed GaugeShape :RadDiagramShape

and defines a custom Symbol dependency property

public static readonly DependencyProperty SymbolProperty = DependencyProperty.Register("Symbol", typeof(string), typeof(GaugeShape), new FrameworkPropertyMetadata(null, OnSymbolChanged));

Whether it’s a standard or a dependency property depends really on what you want to do with it, see the MSDN documentation on this.

Next, you need to define the visual appearance of the control. Here is an important point you need to consider; do you need the adorning elements (resizing adorner, connectors, rotation handle) of the RadDiagram framework to appear? If so, the easiest way is to base your XAML style on the base style (using the BasedOn property) from the framework;

<Style TargetType="{x:Type local:GaugeShape}" BasedOn="{StaticResource {x:Type telerik:RadDiagramShape}}">

As a result, all the adorning diagramming elements are already present and your custom shape will take part in the internal mechanics of RadDiagram. If you omit the directive, then the shape will still be part of the diagram, but you will not see or be able to use the resizer, rotation handle, and so on.

From this point on you can define inside the style all you wish, but there are some gotchas:

  • The ContentTemplate does not immediately give access to the (dependency) properties of the class, but instead exposeses the Content property. So, if you want to access the DataContext inside the Content template you have to either assign this data context to the Content, or you need to walk up the visual tree a bit (see below).
  • The EditTemplate can be (and usually is) a totally different template than the ContentTemplate; it allows you to define how the control looks when the user double-clicks the shape and shifts to ‘edit’ mode. A good pattern here would be to set some data in the DataContext, assign the DataContext to the Content, and to access this data bucket both from the ContentTemplate and the EditTemplate. In situations where the EditTemplate is not sufficient you can hook up the routed DoubleClick event and redirect the default editing behavior (showing the EditTemplate) to some custom behavior. For example, in the sample you will notice that the TextShape shows a custom window on double-clicking. One essential elements here is that you need to halt the event bubbling by setting ‘Handled = true’ otherwise you will have both a custom handler active and the EditTemplate visible.

In the content template of the GaugeShape you will see the following bits:

<TextBlock Text="{Binding Path=Name}" Foreground="{StaticResource MetroAccentBrush}" FontWeight="Bold" HorizontalAlignment="Center" /> <telerik:RadRadialGauge OuterBorderBrush="#FF08FF00" Grid.Row="1" Background="WhiteSmoke">

The TextBlock accesses the Name property because the Content contains the Quote information:

var quote = new Quote(Symbol);
YahooEngine.Fetch(new List<Quote> { quote }); this.Content = quote;

On the other hand, if you want your shape to be stretched and resized according to the outer resizing adorners, you should set the following properties:

<Setter Property="HorizontalContentAlignment" Value="Stretch" /> <Setter Property="VerticalContentAlignment" Value="Stretch" />

Finally, in order to have the Symbol property persistent, you need to tell the framework how to serialize it. While this might sound complicated we really made it simple for you to perform this step.  The serialization of a property (say, the Symbol property) amounts to adding an entry in a dictionary:

public override SerializationInfo Serialize() {
    var info = base.Serialize();
    info[“Symbol”] = this.Symbol ?? ""; return info; }

Conversely, if you want to pick up the saved value of the Symbol property you just ask the dictionary for the value:

public override void Deserialize(SerializationInfo info) { base.Deserialize(info); if (info[“Symbol”] != null) this.Symbol = info[SymbolTag].ToString(); }

There is more under the hood than this straightforward serialization alone, please consult the RadDiagram documentation for more serialization goodies.

Once all this is in place you can add the custom shape to the diagram and bind it to the application data like so:

var shape = new GaugeShape
{
        Position = new Point(10, 120)
};
Diagram.AddShape(shape);

Many more possibilities and extension points are at your disposal, several of which are demonstrated in the custom shapes inside the sample application. This elementary overview, however,should get you going and we have made the documentation as complete as possible to guide you through the ins and outs of the RadDiagram framework.

The toolbox: how to add your custom items

The RadDiagram framework does not provide a Toolbox control out-of-the-box. It is too specific a part of the story and could just be used for some diagramming applications. That said, it is not part of the core framework, but we wrote several lines of code that can be used and easily customized for your needs. There is an Assembly that we called Features (Telerik.Windows.Diagrams.Features.dll), which is an extension of the core RadDiagram framework, and contains some nice features. For example, there is a ToolBox control there. It is a very simple Hierarchical ItemsControl that you can populate with a hierarchical data source or manually with ToolBoxGroups and items. On the other hand, the items are not much more than ContentControl, so you can effectively add any UI Elements you would like to the toolbox(i.e. you can even add regular shapes from the RadDiagram framework)

<expandertoolbox:DiagramToolbox> <expandertoolbox:ToolboxGroup Header="Shapes"> <expandertoolbox:ToolboxItem Header="Rectangle" Description="A simple rectangle"> <local:ShapeToolboxItem Geometry="{telerik:CommonShape ShapeType=RoundedRectangleShape}"/> </expandertoolbox:ToolboxItem> <expandertoolbox:ToolboxItem Header="Ellipse" Description="A simple rectangle"> <local:ShapeToolboxItem Geometry="{telerik:CommonShape ShapeType=EllipseShape}"/> </expandertoolbox:ToolboxItem> </expandertoolbox:ToolboxGroup> </expandertoolbox:DiagramToolbox>

But the interesting part here is how to handle the drop from the Toolbox to the diagram surface. To make our lives easier, we’re using the Telerik DragDropManager, which automatically handles the start-drag operation of the toolbox item. Thus we need to handle the drop operation at the other side, on the diagram surface. 

this.diagram.Drop += this.OnDropToolboxItem;

Let’s take a look at the handler as well.

var item = (e.Data as DataObject).GetData("Telerik.Windows.Diagrams.Features.ExpanderToolbox.ToolboxItem") as ToolboxItem; if (item != null) {
       IToolboxItem toolboxItem = item.Content as IToolboxItem;
       RadDiagramShape shape = null;
       var position = e.GetPosition(this.diagram); if(toolboxItem != null) {
           shape = toolboxItem.CreateShape(position); } if (shape != null) { this.diagram.AddShape(shape);
           e.Handled = true; } }
 

The trickier part is that each type of ToolboxItem implements the CreateShape factory method (from the IToolboxItem interface), which creates a new, configured shape for this type of toolbox item.

public override RadDiagramShape CreateShape(Point position) {
var shape = new ImageShape { Location = this.ImageLocation, Address = this.Address, Position = position, NavigateUri = this.NavigateUri }; return shape; }

The RadDiagram surface properties

There is one more interesting story in this application: How to switch between Edit and Design surface modes. The RadDiagram framework provides you with plenty of properties that can control the read-only state in different aspects. Mentioning these properties here affects the run-time through UI behavior and does not enforce changes through the APIs.

They are:

  • IsEditable - Indicates whether editing is enabled.
  • IsPanningEnabled – Indicates whether panning is enabled.
  • IsZoomEnabled - Indicates whether zooming is enabled.
  • IsResizingEnabled - Indicates whether shape resizing is enabled.
  • IsRotationEnabled - Indicates whether shape rotation is enabled.
  • IsDraggingEnabled - Indicates whether shape dragging is enabled.
  • IsConnectorsManipulationEnabled - Indicates whether connection creating is enabled through the connectors.
  • AllowDelete – Indicates whether item deletion is enabled.
  • AllowDrop – Indicates whether the diagram can accept drop.
  • AllowCopy – Indicates whether item copying is enabled.
  • AllowPaste – Indicates whether item pasting is enabled.
  • SelectionMode – Can choose the selection mode through enumeration:
    • None – selection is disabled.
    • Single – only one can be selection either with Rectangle selection tool or pressing CTRL key.
    • Multiple – selecting items on each click and with Rectangle selection tool.
    • Extended – selecting items with CTRL or using Rectangle selection tool.

To conclude

Much more to discover

[Picture above] Please visit the documentation on RadDiagram for much more info on other aspects not touched by this overview article.

 

While this demo application shows off some of the more juicy features of RadDiagram it is by no means the end of the story. You are invited to continue reading on:



About the Author

Miroslav Miroslavov

is XAML enthusiast. You can follow him on Twitter at @mmiroslavov.

 

Related Posts

Comments

Comments are disabled in preview mode.