Welcome to MSDN Blogs Sign in | Join | Help

Now on CodePlex – VisioVDX: a library to generate Visio VDX Files (without Visio)

A follow-up to my previous post, as promised the library is now on CodePlex. You can find it checked in the source tree used by the VisioAutomation project.

If you browse the source code you’ll see a separate folder with the VisioVDX code in it.

image

NOTES

  • The project is in a separate folder from VisioAutomation to help ensure that it takes no dependencies on Visio binaries.
  • This is very much *alpha* quality
  • Unit tests provide samples of how to use the library
Posted by saveenr | 0 Comments

Creating a Visio VDX File without using Visio

Take a look at this simple Visio diagram

image

What separates it from every other document I’ve shown you? it was generated on a machine that didn’t even have Visio 2007 installed.

About a year ago in the middle of my work on VisioAutomation I had written some code to generate VDX files by directly creating XML instead of automating Visio. At the time my goal was to create an ASPX page that could generate Visio charts on demand.

This mostly worked (for simple diagrams) but had one core limitation – it still required someone to have the Visio Primary Interop Assembly. With the latest code, now there is no connection at all to the PIA – I could, for example, use this code with Mono running on Ubuntu to generate the same file.

I’ll be creating a new CodePlex project with the source code shortly. Keep in mind just a few things. First, it isn’t magic – it still requires someone to have an understanding of Visio’s shapesheet concept. Second, a lot of the layout smarts have to be replicated – so for example if you want to automatically layout charts you’ll have to use something like MSAGL or GraphViz to place things. Third, to generate the output VDX it requires an input VDX (this is where it gets masters from).

As a preview, here’s a screenshot of the code from one of my unit tests. You should get a good idea of how this library works from the example below.

image

Posted by saveenr | 0 Comments

Visio: Controlling Visio 2007 via Powershell cmdlets – VisioPS

I just noticed my VisioAutomation library was mentioned in Episode 84 of the PowerScripting Podcast – And that made me realize there’s very little explaining how to use the VisioPS powershell module. So, for those who are curious I’ve recorded a quick demo on Vimeo.

 

This demonstration will show you how to get started with the module and show you how to perform some simple tasks.

 

Link to Video

http://www.vimeo.com/6783783

 

image

Posted by saveenr | 0 Comments

Dynamics AX 2009: Business Intelligence – A more efficient previewing experience with SSRS reports

So far, whenever I’ve shown how to develop SSRS reports in Dynamics AX 2009 I’ve always shown the preview and the report model as separate tabs that we have to switch to

 

image

This is a pit painful because one can’t see changes to the report immediately, one always has to select the Preview tab

 

image

 

A BETTER WAY – SEE BOTH AT THE SAME TIME

If you have both the report model up and the preview you can see them by right-clicking on one of the tabs and selecting “New Vertical Tab Group”

image

Doing so will result in this …

 

image

 

Now you can see both at the same time.

 

MANAGING TABS AND TAB GROUPS

Once you are using tab groups, you’ll notice that you can manage which tabs appear in which groups by right-clicking on a tab

image

 

This is useful if you have multiple previews for multiple designs and want to put all the previews into a single tab group.

 

HOW TO SEE CHANGES IMMEDIATELY

For example, suppose we start of with the preview and the report model both visible

image

In this case, clearly we don’t have any templates assigned.

 

So click on the report

image

And set a template …

image

the preview is unchanged

 

image

So, just click somewhere on the preview UI or hit the Refresh button

image

 

And that click will cause the preview update

 

image

Posted by saveenr | 0 Comments

Releasing a new version of my VisioAutomation library (version 2.0.0)

Today I’m releasing the latest version of the VisioAutomation library on CodePlex: http://visioautomation.codeplex.com/

This was a very large update and took about 6 months of effort.

CHANGES SINCE 1.X

  • The library itself has been reorganized into several distinct pieces (each in a distinct namespace)
    • VisioAutomation – the core low-level library – I don’t expect people to spend much time using this directly
    • VisioAutomation.Scripting – if you are writing interactive tools that work with Visio then this is the part of the library that will make using controlling Visio much easier
    • VisioAutomation.DOM – This one is a document-oriented API to control Visio – consider it low-level, you generally don’t need to interact with it
  • The tools have been reorganized
    • Visio Power Tools – this provides some extra features to Visio (such as Exporting to XAML) and the ability to create really nice gradients
    • VisioInteractive - (Experimental) A library meant for use by an interactive IronPython 2.0 session
    • VisioPS - (Experimental) an Module for IronPython 2.0 that lets you control Visio from the command line

 

FUTURE PLANS

  • VisioPS will be pulled into its related project I am working on – I haven’t finished with the concept but essentially think of it is a “simple business intelligence & analytics from the command-line” – the idea is to make it easy to play and render human-scale data
  • VisioAutomation – evolutionary changes
  • VisioAutomation.XML – A library to create Visio .VDX files directly from C# without having Visio installed (yes, it’s possible and it’s not even that hard)

PARTING THOUGHTS

  • Even if you aren’t interested in using the code for the library, check out the Visio Power Tools add-in – it add some nice end-user features.
Posted by saveenr | 2 Comments

Edge Rendering Improvement in Visio 2010

I pay abnormally close attention to pixels and so it was with great pleasure this week that I discovered that Visio 2010 addressed a long-standing visual visual quality issue.

HOW VISIO 2007 EXHIBITED THIS PROBLEM

First, I let’s take a look at the Situation in Visio 2007

Start with an ellipse – any shape could be used but it’s most obvious with a curved shape.

image

 

Take a good look at the edges …

image

Do you see how the edge is nice and smooth?

Now fill it with color.

image

The edge is nice and smooth.

If we remove the line …

image

the edge is still smooth

Now grade a 2-color gradient fill (Here is how to do this in a previous blog post)

image

Not so nice.

As you know, I love gradient fills – especially with multiple transparencies. So this was always a sore point when I used Visio 2007.

The best I could ever manage was to work-around the problem by picking an border color.

As you see if you pick set a border, the edge will be smooth again.

image

My work-around was to set the border to some “nice” value that made the less visible to the eye. In this case, I might have picked a simple gray color.

image 

As you can see adding a border minimized the effect.

If you compare the black border to the gray one in the example below, you can see that one can approximate the look of a smooth edge with no border for a gradient fill in Visio 2007

image image

However, it is difficult time find such a color in many cases – especially you have many overlapping shapes or transparencies.

 

VISIO 2010 FIXED THIS PROBLEM

Visio 2010 addresses the problem.

Here’s the a similar gradient fill in Visio 2010

  image

As you can see the edge is smooth – despite the fact it is a gradient fill with no border.

ANOTHER EXAMPLE IN VISIO 2007

Here is a more complex use of gradient fills and transparencies in Visio 2007

image

 

Let’s zoom in …

image

 

AND HOW IT APPEARS IN VISIO 2010

snap0282

 

And zoomed in …

image

Much better!

 

PARTING THOUGHTS

  • Again, it is very good to see that this has improved – a lot of the diagrams I build make use of gradient fills so this is has a big impact for me.
Posted by saveenr | 0 Comments

Simplifying enumeration of Office object model collections with Linq and Extension methods

I found an interesting post on Deborah's Developer MindScape  (via Greg’s blog )and wanted to share a modification of the technique that can simplify the use of Office object models in C# and VB. I use this heavily in my VisioAutomation library.

 

First, let’s look at the the Deborah’s original solution :

var query = from d in Wd.Documents.Cast<Word.Document>()
            select d.Name;

SIMPLIFYING WITH EXTENSION METHODS

This works fine. Through the use of extension methods we can make this even more succinct. The core pain to address is the need to re-enter the type (“Word.Document”) when it is already clear that is the only possible kind of object in the collection

A simple extension method makes this even easier:

var query = from d in Wd.Documents.AsEnumerable()
            select d.Name;

The extension method that achieved this is trivial

public static class WordExtensions
{
    public static IEnumerable<Word.Document> AsEnumerable(this Word.Documents docs)
    {
        return docs.Cast<Word.Document>();
    }

}

SOURCE CODE

The full source code is below ( you can get the entire project from my SkyDrive)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Word = Mi2crosoft.Office.Interop.Word;

namespace DemoOfficeCollectionsIEnumerable
{
    class Program
    {

        static void Main(string[] args)
        {
            before();
            after_with_an_extension_method();

        }

        public static void before()
        {

            // Start Word and get Application object
            var Wd = new Word.Application();

            // Define documents
            var doc1 = Wd.Documents.AddEmptyDoc();
            var doc2 = Wd.Documents.AddEmptyDoc();

            // Use Linq to access the document names.
            var query = from d in Wd.Documents.Cast<Word.Document>()
                        select d.Name;
            var docsnames1 = query.ToList();

            // Or use Lambda expressions
            var query2 = Wd.Documents.Cast<Word.Document>().Select(d=> d.Name);
            var docnames2 = query2.ToList();

        }

        public static void after_with_an_extension_method()
        {
            // Add to the top of the code file

            object missingValue = System.Reflection.Missing.Value;

            // Start Word and get Application object
            var Wd = new Word.Application();

            // Define documents
            var doc1 = Wd.Documents.AddEmptyDoc();
            var doc2 = Wd.Documents.AddEmptyDoc();

            // Use Linq to access the document names.
           
var query = from d in Wd.Documents.AsEnumerable()
                        select d.Name;

            var docsnames1 = query.ToList();

            // Or use Lambda expressions
            var query2 = Wd.Documents.AsEnumerable().Select(d => d.Name);
            var docnames2 = query2.ToList();

        }

    }

    public static class WordExtensions
    {
        public static IEnumerable<Word.Document> AsEnumerable(this Word.Documents docs)
        {
            return docs.Cast<Word.Document>();
        }

        public static Word.Document AddEmptyDoc(this Word.Documents docs)
        {
            object missingValue = System.Reflection.Missing.Value;
            return docs.Add(ref missingValue, ref missingValue,
                                   ref missingValue, ref missingValue);
        }
    }

}

PARTING THOUGHTS

  • I through in an extra extension method (AddEmptyDoc) and liberal use of ‘var’ to make the sample source code smaller
Posted by saveenr | 0 Comments

Dynamics AX 2009: Business Intelligence – Adding Links (via URL Drill Through) to Reports

In this post we are going to learn how to make reports that have links in them.

As always, I start with some sample data. In this case, it will be a list of my favorite blogs.

 

START WITH THE DATA

First, I create a new Data Method

image

image

 

This is the source code for that Data Method

 

[DataMethod(), AxSessionPermission(SecurityAction.Assert)]
    public static System.Data.DataTable DataMethod1()
    {
        var favorite_blogs = new []
        {
            new {
                    Name="Visio Guy",
                    Url ="http://www.visguy.com/"},
            new {
                    Name="Greg's Cool [Insert Clever Name] of the Day",
                    Url ="http://coolthingoftheday.blogspot.com/"},
            new {
                    Name="DisplayBlog",
                    Url ="http://www.displayblog.com/"}

        };

        var datatable = Isotope.Data.DataUtil.DataTableFromEnumerable(favorite_blogs);
        return datatable;
    }

 

You can see from this example how easy it is to create a quick dataset via anonymous types.

 

And then create a new Data set …

 

image

And set the properties as appropriate to point to the Data Method

 

image

CREATE A DESIGN

Now just drag the Data Set into the Designs node and assign some style templates and preview…

image

The column layout isn’t perfect (we’ll correct that later).

So far what we have is just text. If you move the mouse over the URLs they are not treated as URLs but plain text. You can see from the screenshot below that although the cursor is right over the URL that the mouse retains it’s Arrow shape which indicates that this is just plain text.

 

image

Our next step will be to make them clickable.

 

ADD A URL DRILL THROUGH ACTION

 

Expand the design and find the Data > Url field and right click and select URL Drill Through Action

 

 

image

A new node will appear …

image

Examine its properties. We need to set the Expression value to something useful.

 

image

Click on that field and select “=Fields!Url.Value”

image

image

 

 

Now preview the report and move the mouse over a URL

image

As you can see, the cursor now has a hand shape. If you click a new window will launch to that URL

image

 

image

 

At this point we have the basics done. Let’s optimize the report.

 

HIDING THE RAW URLS

We don’t want to show the URLs in the report – we want the user to click on the NAME of the blog and that should go to the appropriate URL. This is simple to achieve.

Delete the Url from the design

image

Only the Name field will remain in the design. Right-Click on the Name field and add a URL Drill Through Action

 

image

You can see the new node is created.

image  

Examine its properties. And set the Expression value to =Fields!Url.Value

image

The thing to notice here is that although the Url field has been deleted from the design (what is shown) of the report, the Url field from the data set that is bound to the report.

Now preview the report

image

 

As expected there is only one column. The URLs are not visible.

 

Now move the mouse cursor over on of the links…

 

image

 

And click…

 

image

Perfect. the link now goes to the correct place.

 

IMPROVING THE LAYOUT

Let’s make the Name column wide enough so that the blog names don’t span multiple lines.

Select the Name column.

image

And examine its properties. You can see that the Display Width property controls the width of the column

image 

Let’s change this to 4 inches

 

  image

And preview the report.

 

image

 

LINKS THAT LOOK LIKE LINKS

One final problem remains: Although the links work – they don’t look like links. They still look like plain text.

A straightforward way of fixing this problem is to again look at the properties of the Name field. There’s a section called Style

image 

If you expand that node … you can see there are more options available.

image

Also, you’ll notice the button on the right with the ellipsis. Click on that.

 

image

And you’ll get a special dialog called the Cell Style editor

 

image

 

Set the color to Blue

image

And the Decoration to Underline

image 

And click OK.

Now preview the report.

image

Done. We have a report that has simple clickable links.

 

SOURCE CODE

You can get it here: http://cid-19ec39cb500669d8.skydrive.live.com/browse.aspx/Public/Dev/SampleCode/Dynamics/SaveenR-Blog-Post-%7C52009-08-12%7C6?view=details

Posted by saveenr | 1 Comments

A Walkthrough of Dynamically Compiling C# code

One of my side-projects requires me to build some of my own tools. In this case: a code generation tool. In a future post, I’ll describe the tool and provide its source, but for now I did want to share some of what I discovered on the way.

First, the tool I am building essentially reads a simple DSL and generates C# source code from it. To be more specific it doesn’t just generate C# source code, it also compiles it into an assembly for you so that it is easy to consume in binary form. It’s this last part I will focus on: taking c# code and making it into an assembly.

I created a simple Console application called DemoCompiler. The entire source is below. I’ll walk you through it section-by-section to illustrate what is going on.

THE SOURCE CODE TO GET STARTED

 

using System;

using System.Collections.Generic;

 

namespace DemoCompiler

{

    class Program

    {

        static void Main(string[] args)

        {

 

 

            // Create the source code

            string source = @"

 

namespace Foo

{

 

    public class Bar

    {

        static void Main(string[] args)

        {

            Bar.SayHello();

        }

 

        public static void SayHello()

        {

            System.Console.WriteLine(""Hello World"");

        }

    }

}

";

 

            // Setup for compiling

            var provider_options = new Dictionary<string, string>

                         {

                             {"CompilerVersion","v3.5"}

                         };

            var provider = new Microsoft.CSharp.CSharpCodeProvider(provider_options);

 

            var compiler_params = new System.CodeDom.Compiler.CompilerParameters();

 

            string outfile = "D:\\Foo.EXE";

            compiler_params.OutputAssembly = outfile ;

            compiler_params.GenerateExecutable = true;

 

            // Compile

            var results = provider.CompileAssemblyFromSource(compiler_params, source);

 

            // Print out any Errors

 

            Console.WriteLine("Output file: {0}", outfile);

            Console.WriteLine("Number of Errors: {0}", results.Errors.Count);

            foreach (System.CodeDom.Compiler.CompilerError err in results.Errors)

            {

                Console.WriteLine("ERROR {0}", err.ErrorText);

 

            }

 

        }

    }

}

 

FYI – pay attention to the two namespaces that are used here:

  • Microsoft.CSharp
  • System.CodeDom.Compiler

Now run the compiler

image

Excellent. No errors.  Ok, we have a EXE.

Let’s run it…

image

And now step through the code

image  

 

TIP: Always check for compile errors

Now let’s play around with it and see what happens.

 

USING OBJECTS ANOTHER ANOTHER ASSEMBLY

First.  let’s try creating a simple Rectangle from System.Drawing.Rectangle and printing it.

 

 

 

            // Create the source code

            string source = @"

 

namespace Foo

{

 

    public class Bar

    {

        static void Main(string[] args)

        {

            Bar.SayHello();

        }

 

        public static void SayHello()

        {

            System.Console.WriteLine(""Hello World"");

            var r = new System.Drawing.Rectangle(0,0,100,100);

            System.Console.WriteLine(r);

 

        }

    }

}

";

This time the compile doesn’t work…

image

 

The reason is that the output assembly doesn’t contain a reference to System.Drawing – we fix that very simply by modifying the compiler parameters

 

 

            string outfile = "D:\\Foo.EXE";

            compiler_params.OutputAssembly = outfile ;

            compiler_params.GenerateExecutable = true;

 

            compiler_params.ReferencedAssemblies.Add("System.Drawing.Dll");

And try compiling…

image

And then running the EXE

 

image

 

USING LINQ

We love LINQ these days, so let’s try using it to print the numbers from 0 to 9

            // Create the source code

            string source = @"

 

using System.Collections.Generic;

using System.Linq;

namespace Foo

{

 

    public class Bar

    {

        static void Main(string[] args)

        {

            Bar.SayHello();

        }

 

        public static void SayHello()

        {

            System.Console.WriteLine(""Hello World"");

            var r = new System.Drawing.Rectangle(0,0,100,100);

            System.Console.WriteLine(r);

            System.Console.WriteLine( string.Join("","", Enumerable.Range(0,10).Select(n=>n.ToString()).ToArray() ) );

 

        }

    }

}

";

 

image

What could be wrong here? We are missing a reference to “System.Core.Dll” (that’s where Linq is)

 

            string outfile = "D:\\Foo.EXE";

            compiler_params.OutputAssembly = outfile ;

            compiler_params.GenerateExecutable = true;

 

            compiler_params.ReferencedAssemblies.Add("System.Drawing.Dll");

            compiler_params.ReferencedAssemblies.Add("System.Core.Dll");

 

Now try compiling.

image

It works, so run the EXE …

image

Perfect.

 

WHAT WE LEARNED

  • the basics of compiling source
  • How to tell if the compilation worked correctly
  • how to specify that an executable is created
  • how to ensure that we can use C# 3.0 syntax
  • how to address common issues in using Linq and referring to other DLLs

 

CREATING A DLL INSTEAD OF AN EXE

This is very simple

 

            string outfile = "D:\\Foo.DLL";

            compiler_params.OutputAssembly = outfile ;

            compiler_params.GenerateExecutable = false;

Just set the output filename to end with “.DLL” and set GenerateExecutable to false.

If you run the compiler now, it will generate a DLL that you can import into another project.

image

 

SOURCE CODE

You can get it here: http://cid-19ec39cb500669d8.skydrive.live.com/self.aspx/Public/Dev/SampleCode/Blog-Post-Samples/Saveenr-Blog-Post-%7C52009-08-11%7C6.zip

Posted by saveenr | 3 Comments

Visio 2007: An single XML file with all of Visio 2007 ShapeSheet sections, rows, cells, and functions

Not a provocative title for this blog post, but it is what it is.

This week I needed to programmatically generate from C# from the list of sections, rows, cells, etc in Visio. My first discovery is that this information doesn’t already exist in a single place – it’s scattered over many pages in MSDN.

Fortunately I also discovered two things:

Combining those two things with some C# code I was able to extract a single file that contains all the information into a single XML file.

GET THE XML FILE HERE

You can download the file from my SkyDrive here: http://cid-19ec39cb500669d8.skydrive.live.com/browse.aspx/Public/Visio/Developer%20Information/ShapeSheet-Reference

Posted by saveenr | 0 Comments

Dynamics AX 2009: Business Intelligence – Dynamically Generating Bitmap Images for SSRS Reports using Data Methods

In my last post I took a detour from the Data Method topic and explored how to put bitmaps into reports. This post is going I’ll merge the two topics – instead of embedding and image or retrieving it from another source we are going to build a report that creates bitmaps on-the-fly and places them in report designs.

 

This technique has several uses

  • You can generate custom charts & graphics
  • You can create images that are context-sensitive (you could for example show the time the report was rendered as a clock, instead of showing it as text in HH:MM format)
  • You can make some very nice looking title bars or backgrounds using effects that are not possible from the SSRS reporting tools directly

 

First, verify that you can create a precision decision that contains an embedded image (you can start with the source code from my previous blog post)

image

Verify that it renders in preview

image

Good. Now that we have a working report, let’s get some dynamic bitmap content there.

First create a new Data Method

image

Here’s what was created …

image 

We are going to change the return type to byte[] and replace the exception with some simple code that uses things in the System.Drawing namespace. So, first we should add a reference to System.Drawing

In the Solution Explorer, right click on BusinessLogic > References and click Add Reference

image

image

Now modify Data Method

[DataMethod(), AxSessionPermission(SecurityAction.Assert)]
public static byte[] DataMethod1()
{
    using (var bmp = new System.Drawing.Bitmap(600, 200))
    {
        var brush_white = System.Drawing.Brushes.White;

        using (var g = System.Drawing.Graphics.FromImage(bmp))
        {
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;

            var f = new System.Drawing.Font("Courier", 36.0f);
            g.DrawRectangle(System.Drawing.Pens.Red, 10, 10, 400, 100);

        }

        var memstream = new System.IO.MemoryStream();
        bmp.Save(memstream, System.Drawing.Imaging.ImageFormat.Png);
        var bytearray = memstream.ToArray();
        return bytearray;

    }

}

All this method does is create a simple bitmap with a red rectangle in it and then returns that bitmap as a byte array.

Build the solution and select the image in the Precision Design and examine its properties

image

As you can see it refers to the an Embedded image with the id “Flowers”

First, we change the Source property

image

 

From Embedded to  Database

image

And then change the Value property from “Flowers”

image

To an “Expression”. click on the Expression option.

image

And the Edit Expression dialog will launch

image

As you can see, it retains the original value of “Flowers”. This is not in valid expression syntax so that is why the red underline appears.

image

We know we have a datamethod that generates a bitmap so let’s find it. Click on Data Methods in the left-most pane on the bottom

image

You can now see all the Data Methods in the project. DataMethod1 is the one that creates the bitmap

image 

So select the text in the expression text box

image

And replace it with an expression that calls DataMethod1

image

And click OK

image

And then you’ll see this …

image

I know. Unsatisfying. When images are generated dynamically via datamethods the design surface doesn’t show a preview of the bitmap.

So, what about preview …

image

Coo. This works.

IMPORTANT TIP

An issue you’ll discover when generating bitmaps dynamically is that the preview window doesn’t pick up changes to the bitmap if you simply rewrite the bitmap-generation code or even some changes in the design surface layout even if you click the Refresh button. So to “force” it to pick up the changes I often close the preview window, rebuild the project, and launch the preview window again.

 

A MORE COMPLICATED DRAWING

I added a new Data Method that creates a more interesting bitmap (the source code for this project includes the code to create this image). This one features some text and three radial gradient fills with transparencies. My intention is to show you how to use this as a header for a report.

image

First make the header area larger by resizing it …

image

 

 

 image

Now select the edge of the image on the design surface

image

And drag it into the header area

image

You’ll see this …

image

And position it toward the top of the report. (I also changed the size of the image on the design surface but that is not important)

image

And when you preview …

image

At this point should you should have a good handle on what can be done with dynamic generation of bitmaps in reports.

 

SOURCE CODE

You can get it here: http://cid-19ec39cb500669d8.skydrive.live.com/browse.aspx/Public/Dev/SampleCode/Dynamics/SaveenR-Blog-Post-%7C52009-08-06%7C6

Posted by saveenr | 0 Comments

Dynamics AX 2009: Business Intelligence – Bitmap Images into SSRS Reports and an Introduction to Precision Designs

Up until now I’ve been talking about data and code that generates it with Data Methods . In this post, I’ll show you how to put images into your reports.

First let’s get an image. 

I found one of the sample Windows 7 pictures and made it smaller

image

and then placed that image on my My Pictures folder on the SSRS server.

image

Now lets go back into Visual Studio. I have a simple report defined that renders a table.

image

The report looks like this when previewed …

image

 

Now let’s just add an image to the report by selecting the Images node and clicking Add Image

image

An Image was created called “Image1” – Just rename this to flowers

image

image

And examine its properties

image

Now we need to select the flowers.png file. How? It isn’t obvious at all – you need to click on the field called Base64 Data

image

And then select a suitable bitmap

image

And now you’ll see that the bitmap is loaded into the report.

image

At this point you are expecting me to somehow drag this image into the report or use it as the background of some thing on the page – but that’s not possible. Auto Design reports  weren’t created to let you put things like images on a page. We need to move into the more complicated world of Precision Design reports.

Fortunately, our work on the original report is NOT wasted. We can transform the Auto Design into a Precision design very easily.

Just right-click on the Auto Design and select Create Precision Design

image 

This will create keep the existing Auto Design but create a new Precision design that is an exact copy of the Auto Design…

image

And if you preview it …

image

You’ll see, that it does indeed look exactly like the original AutoDesign – it even has “AutoDesign1” as the title.

image

The Precision design editing experience is much different though. We can access it by double-clicking on the precision design or right-clicking it and selecting Edit Using Designer

 

image

And now we see the Precision Design editing surface. As you can guess, now that we have a surface we can place report elements exactly where we want them. We get exact control over placement but at the cost of simplicity.

image

There’s nothing in the UI that shows what we can put on the surface yet. So, from the View menu select Toolbox

image

And now a list of report elements is available for you to use

image

Click and hold down on the Image element in the Toolbox

image

And drag it onto the white area of the Precision Design

image

This will leave a tiny icon there. The red x icon appears because we haven’t selected a valid image yet.

image

With the image selected, look at the properties window. The Source property is set to External.

image

Because we added (embedded) the flowers.png file to the report change the Source property to Embedded.

image

And then expand the Value property and pick “Flowers”

image

Even without previewing it, you’ll see the flowers show up in the design surface

image

And naturally this works when previewed …

image

KOALAS

What if the image isn’t embedded but is sitting somewhere else – for example on the IIS server that is on the same box as the SSRS server. In this case, I placed kkoalas.png into an folder in the default web site.

image

And validated that I can see the picture when browsing the website with IE.

image

Now go back to the properties for the image we put on the report

image

And set the Source to External

 image

And click on the Value property

image 

Which lets you type into the field directly

image

And enter the url … http://isotopex/images/koala.png

 

image  

And then the design surface will update … to have 100% more Koala

 image

And this is visible in preview, of course

 

image

In this Koala example, the bitmap was on the same server as the SSRS server, we can also point SSRS at images on remote machines

 

Go to the microsoft website …

image

Find an image you want, and right-lick to see its properties

image

image

And you can see the URL there in the Properties dialog

image

Select the text, right-click, and choose Copy

image

Go back to your report …

image 

And change the Value property  …

image

To the new URL …

image

And there you go …

image

NOTE: To fetch images remotely requires that the SSRS Execution account be set correctly (Adding an Image to a Report)

Posted by saveenr | 1 Comments

Dynamics AX 2009: Business Intelligence – the Column Chart Layout for Auto Design reports

I’ve been looking forward to sharing this post for a while. I am going to show exactly how to get a column chart in SSRS using Dynamics AX 2009. I’m going to go step-by-step and show you “gotchas” you will encounter as you develop charts. Although this takes more to do it in this way, ultimately prepares you for the real-world use the reporting components in Dynamics AX.

Ultimately I want a simple column chart showing a list of numbers. Instead of hard-coding the numbers I’ve written a function that generates as many random points as we need. Because we often want to see numbers in a trend, this method generates n numbers from from some starting value to some ending value (i.e. points along a line displaced by some factor)

public static IEnumerable<double> generate_random_sequence(int num_values, double min_value, double max_value,
    double start_value, double end_value, double factor)
{

    double step = (end_value - start_value) / (num_values - 1);
    var r = new System.Random();

    var indices = Enumerable.Range(0, num_values);

    var values = from i in indices
                 let delta = (r.NextDouble() * (max_value - min_value) * factor) - (factor * 0.5)
                 let v = start_value + (i * step)
                 select v + delta;

    var normalized_values = from value in values
                            select System.Math.Min(max_value, System.Math.Max(min_value, value));

    return normalized_values;

}

Now I create a data method …

[DataMethod(), AxSessionPermission(SecurityAction.Assert)]
public static System.Data.DataTable DataMethod_Series_0()
{
    int num_values = 14;
    double min_value = 0;
    double max_value = 100;
    double start_value = 30;
    double end_value = 70;
    double factor = 0.10;

    var values = generate_random_sequence(num_values, min_value, max_value, start_value, end_value, factor);

    var records = values.Select((value) => new { NumWidgets = (int) value } );

    var datatable = Isotope.Data.DataUtil.DataTableFromEnumerable(records);
    return datatable;

}

And then build the project to verify everything compiles.

Now create a dataset

image

Set its Data Source to Business Logic

image 

And select that data method in the Query property for the dataset

image

image

Build the project to check if anything is wrong.

 

Notice that we haven’t altered the Default Layout – it is still set to Table. This is deliberate. When you create any charts, I always advise you first to verify that your datasets render as tables.

image

Now drag the dataset into the Designs node

image

Now preview the report

image

And we see ..

image

Ugly report. But we don’t care how it looks. We just did this to validate the data.

 

Now I’ll create a copy of that same data set

image

And set the Default Layout to ColumnChart

image

And now drag this into the Designs node

image

Now preview ..

image

  

Only to be greeted by …

image

OK, first lesson – we need column groupings.

Maybe you will be tempted to ‘fix’ this problem by going to the NumWidgets field

image

And changing its Field Type from Data to Grouping

image

And if you do that and drag the dataset  into the designs node you’ll get

image

So now you have 2 errors – 1 more than previously so things got worse not better.

The way to solve is is simple. Create an additional field in the dataset that will serve for the category grouping

To do this we need to modify the data method

 

[DataMethod(), AxSessionPermission(SecurityAction.Assert)]
public static System.Data.DataTable DataMethod_Series_1()
{
    int num_values = 14;
    double min_value = 0;
    double max_value = 100;
    double start_value = 30;
    double end_value = 70;
    double factor = 0.10;

    var values = generate_random_sequence(num_values, min_value, max_value, start_value, end_value, factor);

    var records = values.Select((value, index) => new { Index = index, NumWidgets = (int) value });
    var datatable = Isotope.Data.DataUtil.DataTableFromEnumerable(records);
    return datatable;

}

Notice the Select method! This version of the Select method in LINQ is not that well known – it provides the current index of the enumeration

And now delete the dataset and recreate it but bind it to this new data method

image

Good, now we see both fields.

Because the data set is new, the Default Layout is set to table … verify that you can see the table rendering …

 

image

Good so far.

Now set the Default Layout property of that Data set to ColumnChart and drag the data set into the designs node. You’ll get an AutoDesign that previews as …

image

Ugh. Of course – didn’t address the original complaint. We haven’t identified which field to use for the category grouping.

Go to the Index field in the dataset

image

And set the Field Type from Data to Grouping

image

And now drag the dataset into the designs node and preview the report…

 

image

Fantastic – we have an ugly column chart.

I can’t stand looking at this so let’s set a style template

Find the chart element in the AutoDesign

image

And look at its properties. Under the Style Template property you’ll notice there are two different Column Chart styles

image

Let’s try the first one: ColumnChartStyleTemplate

image

Which gives this result …

image

And the second one: ColumnChartStyleTemplateCC

image

Which gives …

image

I like this one better. We’ll stick with it.

 

Now that we are OK with the look of the chart. Let’s fix up the content of the chart.

 

Problem #1 – look at the Y axis – the smallest value on the axis 30. Why is that?

This is an automatic behavior of the chart. In many cases we’d like to see the Y axis start at zero, of course.

This behavior is controlled by a property on the chart …

image

But wait – it says the min value should be zero. What’s going on?

If you click on the property … you’ll see that the property window contains some additional information.

image

Ah, zero zero means “Auto” … so how do I get zero? My workaround is simple: I enter a very small value.

image '

Which previews as …

image

Great – now the Y axis shows zero on the bottom.

There is a corresponding property for the top of the Y axis

 

image

It behaves similarly, Data Scale Min Value but for this example I’ll leave it alone.

 

Problem #2 – I can’t see the exact number of widgets.

 

To fix this you’ll have to expand the design nodes and underneath the chart, open the Data node and find the NumWidgets field.

image

And look at its properties … specifically the Display Point Label property

 image

It’s set to False by default, set it to True …

image

And preview …

 

image

Excellent. We have a nice looking column chart

To make it complete I’ll select a template for the report layout …

 

image

image

Which gives …

image

 

 

 

SOURCE CODE

You can get it here: http://cid-19ec39cb500669d8.skydrive.live.com/browse.aspx/Public/Dev/SampleCode/Dynamics/SaveenR-Blog-Post-%7C52009-08-02%7C6?view=details

Posted by saveenr | 1 Comments

Dynamics AX 2009: Business Intelligence – the Matrix Layout for Auto Design reports

Previously with Auto Design layouts, I left off with by saying that some required us to tweak the Datasets to get them to work. In this post, we’ll change the properties of the datasets and see how that enables the Matrix and chart layouts.

First, we need more data. I’ve revised the my Data Method to return more patient data …

using System;
using System.Collections.Generic;
using System.Security.Permissions;
using System.Data;
using System.Linq;

using Microsoft.Dynamics.Framework.Reports;
public partial class Report1
{

    [DataMethod(), AxSessionPermission(SecurityAction.Assert)]
    public static System.Data.DataTable DataMethod_Patient_Data()
    {
        int max_age = 60;
        int min_age = 18;

        int min_weight = 140; // weight in pounds
        int max_weight = 240;

        var areas = new[] { "Thoracic Surgery", "Emergency", "ENT" };
        var doctors = new [] { "Reddy", "Jackson", "Tordilla" };

        var r = new System.Random();
        var names = new string[] {      "Akuma", "Ryu", "Ken",
                                        "Guile", "M.Bison" ,
                                        "Chun-Li", "Cammy" ,
                                        "Blanka", "E.Honda",
                                        "Gen", "Birdie", "Adon",
                                        "Sagat", "Dhalsim", "Zangief",
                                        "Balrog", "Vega"};

        var records = from name in names
                      select new
                      {
                          Name = name,
                          Age = r.Next(min_age, max_age),
                          Weight = r.Next(min_weight, max_weight),
                          Area = areas[ r.Next(0, areas.Length) ],
                          Doctor = doctors [ r.Next(0, doctors.Length)] ,
                          Hypertension = (r.NextDouble() > 0.9) ? true : false,
                          Diabetes = (r.NextDouble() > 0.85) ? true : false,
                          Asthma = (r.NextDouble() > 0.75) ? true : false

                      };

        var datatable = Isotope.Data.DataUtil.DataTableFromEnumerable(records);

        return datatable;

    }

}

 

And then create a Data set that uses this Data method …

image

And when I drag it into the Designs node a new Design is created which I renamed to AutoDesign_Table_0 and set the styles for the layout and the table. The results are this.

image

Instead of modifying that Data set we will duplicate it using Copy

image

And then Paste

image

Which created this Dataset

image

And I will rename this to “Dataset_PatientData_1”

image

image

And set the Default layout to Matrix

image

And now drag it into the Designs node. A new AutoDesign is created. When you try to preview the design …

image

Obviously something is missing … let’s focus on the errors.

 

image

We obviously need to set something.

For this report, let’s say we want have a question about the number patients, we want to know who is treating them and what these patients are doing at the hospital.

In other words we want a matrix like this …

image

 

Go back to the dataset, click on Doctor and look at the properties for the field

image

The Grouping Type is set to category which is what we want

image

But the Field Type is set to Data. This we want to change.

image

We’ll set it to Grouping

image

OK, now the Doctor field is set up correctly.

image

After this modification, If we try to drag the dataset into a design and preview we’ll see …

image

This is better, now there’s only one error …

 

image

We are still missing column groupings.

We wanted the columns to be by “Area”, so let’s go to that field in the Data set

image

And examine it’s properties. Grouping Type is set to Category - we want to change this to Series

image

image

And Field type is set to Data. We’ll change this to Grouping.

image

image

Now the data set is ready.

image

Drag the dataset on to the Designs node and preview …

image

At least preview works.

But we need to fix this - we don’t want to see all the patient information, just the number of patients.

A simple way of fixing this up is expand the newly-created design

image

And then remove the data fields we don’t care about – just leave the Name field

image

If we drag preview the design now we will see …

image

Which is better.

Now we want to see the numbers of distinct patients, not their names.

So field the name field in the design.

image

And examine its properties. We are going to focus on the Aggregate Function from None

image

to CountDistinct

image

Now preview the report …

image

Almost what we want. But it looks ugly. Let’s set the style templates and see what happens.

image

Almost done.

Now we want to get rid of the “Name” on each column though.

image

Let’s look at the Name field in the design

image

And examine its properties. We will change it’s Caption property

image

by removing the expression and leaving it blank

image

Now preview the report…

image

Done.

 

SOURCE CODE

You can get it here: http://cid-19ec39cb500669d8.skydrive.live.com/browse.aspx/Public/Dev/SampleCode/Dynamics/SaveenR-Blog-Post-%7C52009-07-29%7C6?view=details

Posted by saveenr | 0 Comments

A List of Tools for Automatic Graph and Diagram Layout

Creating diagrams and graphs programmatically is one of passions. Below is a set of links you may find useful if you want to incorporate these techniques into your own applications. Where possible I’ve added licensing information.

 

GraphViz

http://www.graphviz.org/

Made by: ATT

License: Open Source CPL

Notes: GraphViz is a set of native (unmanaged) applications (dot.exe, neato.exe, etc.). Using them from a .NET language means calling an EXE with text input and text output.

Diagram.NET

http://www.dalssoft.com/diagram/

http://code.google.com/p/diagramnet/

License: Apache License 2.0

Microsoft Automatic Graph Layout

http://research.microsoft.com/en-us/projects/msagl/default.aspx

License: commercial (license is about $300)

Notes: I’ve used this in my projects – relatively easy to use and produces great results.

July 2009: there’s a limited time promotion code for purchasing a license for only $99

ILOG Diagram for .NET

http://www.ilog.com/products/diagramnet/

License: commercial

Flare

http://flare.prefuse.org/

License: BSD

UbiGraph

http://ubietylab.net/ubigraph/

 

Omnigator

http://www.ontopia.net/omnigator/models/index.jsp

 

aiSee

http://www.aisee.com/

 

Graph#

http://www.codeplex.com/Wiki/View.aspx?ProjectName=graphsharp

 

Circos

http://mkweb.bcgsc.ca/circos/

License: GPL

 

Pajek - Program for Large Network Analysis

http://pajek.imfm.si/doku.php

http://vlado.fmf.uni-lj.si/pub/networks/pajek/

 

Cytoscape

http://cytoscape.org

 

Piccolo

http://www.cs.umd.edu/hcil/piccolo/index.shtml

 

Data Visualization Components from Microsoft Research

http://research.microsoft.com/en-us/downloads/dda33e92-f0e8-4961-baaa-98160a006c27/default.aspx

License: commercial

 

Treemaps

http://www.cs.umd.edu/hcil/treemap/

http://www.cs.umd.edu/hcil/photomesa/download/layout-algorithms.shtml

Squarified Treemaps in XAML & C# using Microsoft Longhorn - http://www.codeproject.com/KB/recipes/treemaps.aspx

 

QuickGraph

http://www.codeproject.com/KB/miscctrl/quickgraph.aspx?display=Print

License: zlib/png license

 

NodeXL

http://www.codeplex.com/NodeXL

Posted by saveenr | 0 Comments
More Posts Next page »
 
Page view tracker