ZedGraph C# Graph Data Export to CSV Using a Custom Context Menu

In continuation of my earlier post on ZedGraph example which plots a sinosoidal graph, I have extended it further to:

Add a new custom menu item in context menu(which appears on right click on the graph)

Export Graph plot data to CSV (coma separated values) file. Which can be opened by spreadsheets such as Microsoft Excel and Open Office calc.

For the custom context menu, the code has been derived from ZedGraph Wikipage. The following is the code of the Windows Form which has the ZedGraph control.

[sourcecode language=’c#’]
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using ZedGraph;
using System.IO;

namespace ZedGraphTest
{
public partial class Form1 : Form
{
private PointPairList m_pointPairList;
//CSV Writer
private StreamWriter m_CSVWriter;

public Form1()
{
InitializeComponent();
CreateGraph();
SetSize();

//csv
zedGraphControl.ContextMenuBuilder +=
new ZedGraphControl.ContextMenuBuilderEventHandler(MyContextMenuBuilder);
}

private void CreateGraph()
{
GraphPane myPane = zedGraphControl.GraphPane;

// Set the titles and axis labels
myPane.Title.Text = “ZedGraph Test”;
myPane.XAxis.Title.Text = “theta (angle)”;
myPane.YAxis.Title.Text = “Sin (theta)”;

// Make up some data points from the Sine function
m_pointPairList = new PointPairList();
for (double x = 0; x <= 360; x += 10) { double y = Math.Sin(x * Math.PI / 180.0); m_pointPairList.Add(x, y); } // Generate a blue curve with Plus symbols, LineItem _myCurve1 = myPane.AddCurve("Sin (theta)", m_pointPairList, Color.Blue, SymbolType.Plus); // Fill the pane background with a color gradient myPane.Fill = new Fill(Color.White, Color.FromArgb(220, 220, 255), 45F); //Make the MajorGrids of Axes visible myPane.XAxis.MajorGrid.IsVisible = true; myPane.YAxis.MajorGrid.IsVisible = true; // Calculate the Axis Scale Ranges zedGraphControl.AxisChange(); } private void Form1_Resize(object sender, EventArgs e) { SetSize(); } private void SetSize() { zedGraphControl.Location = new Point(10, 10); // Leave a small margin around the outside of the control zedGraphControl.Size = new Size(this.ClientRectangle.Width - 20, this.ClientRectangle.Height - 20); } private void MyContextMenuBuilder(ZedGraphControl control, ContextMenuStrip menuStrip, Point mousePt, ZedGraphControl.ContextMenuObjectState objState) { // create a new menu item ToolStripMenuItem _item = new ToolStripMenuItem(); // This is the user-defined Tag so you can find this menu item later if necessary _item.Name = "Export Data as CSV"; _item.Tag = "export_data_csv"; // This is the text that will show up in the menu _item.Text = "Export Data as CSV"; // Add a handler that will respond when that menu item is selected _item.Click += new System.EventHandler(ShowSaveAsForExportCSV); // Add the menu item to the menu,as 3rd Item menuStrip.Items.Insert(2, _item); } private void ShowSaveAsForExportCSV(object sender, System.EventArgs e) { try { //show saveAs CmdDlg saveFileDialog1.Filter = "CSV files (*.csv)|*.csv"; saveFileDialog1.ShowDialog(); m_CSVWriter = new StreamWriter(saveFileDialog1.FileName); WriteCSVToStream(); m_CSVWriter.Close(); MessageBox.Show("CSV File Saved", " ZedGraph ", MessageBoxButtons.OK); } catch (Exception ex) { m_CSVWriter.Close(); MessageBox.Show(ex.ToString()); } } private void WriteCSVToStream() { //First line is for Headers., X and Y Axis string _xAxisHeader = CheckCSVString(zedGraphControl.GraphPane.XAxis.Title.Text); string _yAxisHeader = CheckCSVString(zedGraphControl.GraphPane.YAxis.Title.Text); m_CSVWriter.Write(_xAxisHeader + "," + _yAxisHeader + "n"); //subsequent lines are having data for (int i = 0; i < m_pointPairList.Count; i++) { m_CSVWriter.Write(m_pointPairList[i].X + "," + m_pointPairList[i].Y + "n"); } } private string CheckCSVString(string _string) {//Check to see if there are any characters that can disturb the CSV delimeters. string _returnString = _string; if (_string.IndexOfAny("",x0Ax0D".ToCharArray()) > -1)
{
_returnString = “”” + _string.Replace(“””, “”””) + “””;
}
return _returnString;
}

}
}

[/sourcecode]

Zedgraph C# Graph Plot Example Application

Update : Check out ZedGraph C# Graph Data Export to CSV Using a Custom Context Menu , It has code to make a custom context menu item and also export the graph plot data as CSV.

Zedgraph is a very good opensource C# graph plotting library. Check out more details at my earlier post on Zedgraph. I have gone a step forward and made availabe source code and exe of a sample Zedgraph application which lets you have Line Plot, Bar Graph and Pie Chart.

Download Source Code (Visual Studio 2005 project in C#)

Download EXE

Below are the Screenshots of the Window Application. Copy and paste 2 columns of data from your favorite spreadsheet(eg MS Excel, Open Office Calc etc). NewLine and Tab delimiters are identified and the data is sorted accordingly, and added to graph plots. The Zedgraph plot library is so easy to use, implement and extend that it just took an afternoon to come up with this Windows application, when I was trying to convince my cousin to use ZedGraph in his college project.

ZedGraph is also being used to plot graphs in IN-Motion, a Motion Simulation Addin for Autodesk Inventor which I am co-developing along with my mentor. We are using ZedGraph to plot Postition-Velocity-Acceleration data, and intend to use it further more in Force-Torque graphs etc. Thanks to ZedGraph team for such a wonderful effort 🙂

Figure 1: ZedGraph Sample Window Application

Figure 2: The plot data for Line Plot and BarGraph are copied from a spreadsheat (eg MS Excel) and pasted in the text area. The code then uses tab and newLine delimiters to arrange data for plotting.

Figure 3: Line Plot for the above data. Notice the Titles of the X and Y axes.

Figure 4: Bargraph for the above data.

Figure 5: Data for Pie Chart. Paste 2 columns from spreadsheet. You may also use normal textbox to get the data from the user.

Figure 6: Pie Chart for the above data.

Download Source Code (Visual Studio 2005 project in C#)

Download EXE

Minimize forms along with Parent Application or Form in C#

How to minimize forms that belong to a particular application, when the parent application (In my case Autodesk Inventor) is minimized ? When you create software or addins, you would want the forms/dialogs to be minimized and not floating around when parent application is minimized.

For that we need to deal with hWnd of parent application. “hWnd” stands for Window Handle, which is the API call to the window(parent application). Since we come across this too often in Inventor customization to make addins, I have created a Class and a couple of methods for better clarity. Before I go into details, lets see what are the different types of Forms/Dialogs you would deal while developing Windows based software.

1)Modal Forms or Dialog Box

Modal Form

The modal forms are used when you want the user to enter some values and unless the form/dialog is closed, he/she cannot interact with other controls in the application. All the MessageBox’s are of modal types. The image on the left is also an example of Modal forms. Here, the user has to enter/select details of Graph plots in our addin IN-Motion.


2. Modeless Form

The modeless forms are used when user can enter values into the form and also can interact with other controls in application, even when the form is not minimized. The image on the left is the Simulation playback deck in IN-Motion.


Coming back to our problem of minimizing forms with parent application, below is the code. If the user minimizes Inventor application(parent form), its child forms are also minimized.
[sourcecode language=’c#’]
//
//Declare and set..here m_inventorApplication is the application
//MainFrameHWND returns its handle.
//WindowsWrapperForForm is a Class, defined at the bottom
WindowsWrapperForForm m_windowsWrapperForForm = new
WindowsWrapperForForm((IntPtr)m_inventorApplication.MainFrameHWND);

//Declare and set a form .. ModalCmdDlg is our modal form
ModalCmdDlg m_modalCmdDlg = new ModalCmdDlg();

//Declare and set a form .. ModelessCmdDlg is our modeless form
ModelessCmdDlg m_modelessCmdDlg = new ModelessCmdDlg();

//Show Modal form
ShowModalForm(m_modalCmdDlg);

//Show Modeless form
ShowModelessForm(m_modelessCmdDlg);

//Methods
private void ShowModalForm(Form _modalCmdDlg)
{
_modalCmdDlg.Activate();
_modalCmdDlg.ShowInTaskbar = false;
//ShowDialog is used..for Modal forms
_modalCmdDlg.ShowDialog(m_windowsWrapperForForm);
}

private void ShowModelessForm(Form _modelessCmdDlg)
{
_modelessCmdDlg.Activate();
_modelessCmdDlg.ShowInTaskbar = false;
//Show is used..for Modeless forms
_modelessCmdDlg.Show(m_windowsWrapperForForm);
}

//Below is the code for Class WindowsWrapperForForm
//****************Class***************

class WindowsWrapperForForm : System.Windows.Forms.IWin32Window

{
private IntPtr m_hwnd;
public WindowsWrapperForForm(IntPtr handle)
{
m_hwnd = handle;
}
#region IWin32Window Members
public IntPtr Handle
{
get { return m_hwnd; }
}
#endregion
}
//****************EndClass*******************

[/sourcecode]

Opensource C# Graph Plot Library – ZedGraph

Update: Check out Zedgraph C# Graph Plot Example Application , I have an example ZedGraph Application (with sourcecode) to draw Line Plot, Bar Graph and Pie Chart.

Update 2: Check out ZedGraph C# Graph Data Export to CSV Using a Custom Context Menu , It has code to make a custom context menu item and also export the graph plot data as CSV.

ZedGraph C# Graph Library

I was searching for an opensource(hence free) Graph plotting library in C# (or VB.NET), so that it could be used in our IN-Motion addin for Autodesk Inventor. After some googling, I found 2 suitable open source libraries namely ZedGraph and NPlot. When both websites(read wiki) were compared, I found ZedGraph recently updated and also had great documentation to take off immediately. I readily downloaded the latest version of ZedGraph dll from its SourceForge project and followed the instructions on ZedGraph wiki.

Within no time, I was ready with ZedGraphTest example, whose screenshot is above. It is so simple that, without even exploring, I could accomplish basic graph plotting. Some of the plus points I see in ZedGraph are:

  • Not much tweaking of source-code is required for basic tasks.
  • All the plot elements (line, curve, panel, axes, plot-markers etc) can be set different colors. Even gradients can be set to have crazy as well as good looking Graphs
  • Different types of graphs (line,bar,pie etc) are possible with ease.
  • Using left click on the plot panel, the graph can be zoomed
  • Middle button can be used to pan the plot
  • Upon right click over the plot, a context menu appears which, out of the box has a lot of useful features such as saving the image, toggle the on-hover highligthing etc
The code for my ZedGraphTest is below. I have changed only CreateGraph() method, and the remaining code is same as in the example.
[sourcecode language=’c#’]
private void CreateGraph(ZedGraphControl zgc)
{
GraphPane myPane = zgc.GraphPane;

// Set the titles and axis labels
myPane.Title.Text = “ZedGraph Test”;
myPane.XAxis.Title.Text = “theta (angle)”;
myPane.YAxis.Title.Text = “Sin (theta)”;

// Make up some data points from the Sine function
PointPairList _list1 = new PointPairList();
for (double x = 0; x <= 360; x += 10) { double y = Math.Sin(x * Math.PI / 180.0); _list1.Add(x, y); } // Generate a blue curve with Plus symbols, LineItem _myCurve1 = myPane.AddCurve("Sin (theta)", _list1, Color.Blue,SymbolType.Plus); // Fill the pane background with a color gradient myPane.Fill = new Fill(Color.White, Color.FromArgb(220, 220, 255), 45F); //Make the MajorGrids of Axes visible myPane.XAxis.MajorGrid.IsVisible = true; myPane.YAxis.MajorGrid.IsVisible = true; // Calculate the Axis Scale Ranges zgc.AxisChange(); } [/sourcecode] So far, this library has been a boon to me as I dont have to reinvent the wheel again. Thanks a ton to ZedGraph guys 🙂

Debugging Autodesk Inventor Addin using Visual Studio


Watch High Resolution video on AR-CAD

If you have followed my earlier screen casts on Developing Inventor Addin using C# (Visual Studio) here and here, I had not touched anything on How to debug an Addin using Visual Studio. When you build / register an Addin, a DLL (Dynamic Link Library) file is created which Inventor identifies as an Addin. To be able to debug an Addin, you have to step into Inventor Process. This can be done as follows.

If you are using a free version of Microsoft Visual Basic (Express Edition), it does not have a debugging option for COM objects out of the box. This can be done with the following work around / trick

  • Create a file with a name <yourAddinDllName>.csproj.user (In my case, it is AR-CADInventorAddIn4.csproj.user
  • Put the following content into this file (The only thing that could probably change is the location of your Inventor.exe file)

<Project xmlns=”http://schemas.microsoft.com/developer/msbuild/2003″>

<PropertyGroup Condition=” ‘$(Configuration)|$(Platform)’ == ‘Debug|AnyCPU’ “>

<StartAction>Program</StartAction>

<StartProgram>C:Program FilesAutodeskInventor 2008BinInventor.exe</StartProgram>

</PropertyGroup>

<PropertyGroup>

<ProjectView>ShowAllFiles</ProjectView>

</PropertyGroup>

</Project>

  • Close the solution and open it again. By doing this, the .csproj.user file is associated with the project.
  • Insert a “Break Point” in your code and Start Debugging by hitting F5 key.
  • Now Inventor gets started and you are halted at the break point. Use Step Through and Step Into to inspect different objects, by hovering the mouse over the objects.
  • When you are done with Debugging, your addin would load up and hence Inventor is loaded completely. You can also insert break points when you click on a Custom Button , your addin has created when the Inventor is loaded completely.

If you happen to have a Visual Studio Professional version, there is no need to create the .csproj.user file, you can follow these instructions to get the debugger working.

  • Right Click on your addin project. Go to its properties.
  • Go to Debug Tab listed in the left side of this dialog.
  • Set Configuration = Debug , Platform = Any CPU
  • Set Start External Program to the location pointing to Inventor.exe
  • Close the properties Dialog box
  • In the Solutions Explorer, click on an icon “Show All Files”
  • Carry on with your debugging session as explained above and also in the screencast

I hope things are pretty much clear, if there are any queries, I would love to hear them in the form of comments.

Develop Autodesk Inventor Addin using C# – Part 1

Part 1a

Part 1b

Watch High Resolution video of both above videos on AR-CAD

I hope you have gone through my earlier video tutorial and post, as they provide a good (if not great) foundation for basic concepts of Autodesk Inventor API and how it Inventor can be customized using Visual C#. In the previous posts, we had connected to Inventor as an external exe file, which runs out 0f process with respect to Inventor and hence can be considered slow. To make the addins work faster and to give the end user a better work-flow and experience, we have to make an addin which is internal to Inventor and which runs in-process with respect to Inventor.

In the above videos ( they have been broken into part 1a and 1b as youtube couldn’t upload the whole video, which is 12 mins long), basic introduction is given to “How to develop an addin to Inventor using C#”. Please go through it and I hope the explanation in it is good enough to get you started. In Next versions of this tutorial, I shall try to increase the complexities. If there are any doubts/ clarifications / suggestions, I would love to hear from you as comments to this post. Watch High Resolution video of both above videos on AR-CAD

Customize Autodesk Inventor API using C# – Part 3

In continuation to my previous post on Customizing Inventor using C#, I go a step further and interact with an opened Assembly through API. I have ported the code from VBA to C# for the example explained in Introduction to Inventor API and VBA (Visual Basic for Applications). The attached document is from Autodesk University of 2003.

Start a new C# Windows Application project in Visual Studio 2005, as done in previous tutorial. Design the form as shown in the image to the left. Double clicking on Hide / Show will take you to Form1.cs in the Code Viewer window and add/append the following code into it. Please note that I have changed the Names/Identifiers of form elements to txtSearchName , cmdShow, cmdHide as explained in the above tutorial document.

In this example, when you hit ‘F5’ or Debug, a windows form appears as shown. Type a part name in the Search Field and hit “Hide”. If any part(s) exist in the opened assembly with that name, it/they would be made invisible. If its hidden and you hit on “Show”, the part would be made visible. In our case, we have made Piston part invisible in the engine assembly that ships with Inventor as an example assembly. Save the application by File> Save All in Visual Studio.

You can also use this Windows Application by executing the .exe file that is produced, when you debug/build your application. In my case, its at My DocumentsVisual Studio 2005ProjectsWindowsApplication1WindowsApplication1binDebugWindowsApplication1.exe . Double clicking on the exe file would also popup the Form that was developed.

Form1.cs code

[sourcecode language=’c#’]
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace WindowsApplication1
{
public partial class Form1 : Form
{
//Instantiate a variable with Inventor.Application object.
//It should have a scope throughout this Class
private Inventor.Application oApp=(Inventor.Application)System.Runtime.
InteropServices.Marshal.GetActiveObject(“Inventor.Application”);

//Declare oAsmDoc to have a scope within this Class
private Inventor.AssemblyDocument oAsmDoc;
public Form1()
{
InitializeComponent();

//Check that a document is open
if (oApp.Documents.Count == 0)
{
MessageBox.Show(“An Assembly must be active”);

}
//Check that an assembly document is active
if (oApp.ActiveDocument.DocumentType !=
Inventor.DocumentTypeEnum.kAssemblyDocumentObject)
{
MessageBox.Show(“As Assembly document must be active”);

}
//First Type Cast ActiveDocument into AssemblyDocument
//Set a reference to the active document
oAsmDoc = (Inventor.AssemblyDocument) oApp.ActiveDocument;
}

private void cmdHide_Click(object sender, EventArgs e)
{
//Call the function that traverses the assembly
// and sets the visibility.
SetVisibility(oAsmDoc.ComponentDefinition.Occurrences,
txtSearchName.Text, false);

//Update the View.
oApp.ActiveView.Update();
}

private void cmdShow_Click(object sender, EventArgs e)
{
//Call the function that traverses the assembly
// and sets the visibility.
SetVisibility(oAsmDoc.ComponentDefinition.Occurrences,
txtSearchName.Text, true);

//Update the View.
oApp.ActiveView.Update();
}

private static void SetVisibility
(Inventor.ComponentOccurrences Occurences, string SearchName,
bool VisibilityOn)
{
//Iterate through each of the occurences
//in the collection provided.
foreach (Inventor.ComponentOccurrence oOccurence in Occurences)
{//Check to see if the occurence name matches the search name
//The strings are converted to lower case
// to remove context sensitivity.
if(oOccurence.Name.ToLower().Contains(SearchName.ToLower()))
{//Check to see if the visibility is different than the specified
if (oOccurence.Visible != VisibilityOn)
{//Set the Visibility of the occurence.
oOccurence.Visible = VisibilityOn;
}
}
}
}
}
}
[/sourcecode]

Customize Autodesk Inventor API using C# – Part 2


Watch High Resolution video on AR-CAD

I hope you have gone through my previous posts on Inventor API a) Introduction to Autodesk Inventor API and Customization and b) Customize Autodesk Inventor using C#. It is also assumed that you have gone through DevTV: Introduction to Inventor Programming Video, which is on Inventor Customization page. In the above video, we connect to Inventor API from Visual C# (Visual Studio 2005). I have just replaced the VB.NET code that was used in DevTV tutorial with the corresponding C# code. You can see the comparison below. Please note how GetObject in VB.NET is replaced by a much more lengthier code. If the above youtube video is not very clear, watch it on AR-CAD.

VB.NET Code
[sourcecode language=’vb’]
Dim oApp As Inventor.Application
oApp = GetObject( , “Inventor.Application”)
MsgBox(“Number of open docs = ” & oApp.Documents.Count)
[/sourcecode]

Visual C# Code
[sourcecode language=’c#’]
Inventor.Application oApp;
//The below initialization is on a single line
oApp =
(Inventor.Application)System.Runtime.InteropServices.Marshall.
GetActiveObject(“Inventor.Application”);

int number_int = oApp.Documents.Count;
string number_string = Convert.ToString(number_int);

MessageBox.Show (“Number of open docs =” + number_string);
[/sourcecode]

Customize Autodesk Inventor API using C#

In continuation of previous post on Introduction to Inventor API and Customization, this blog post will show some insights on how to customize Inventor API using Visual C# and Visual Studio 2005.

It is assumed that you have installed Autodesk Inventor (Version 10 or above) and Visual Studio 2005. As per the discussion over Inventor Customization forum, it is suggested that you have Visual Studio 2003 or 2005 for the Inventor Addin Template to work properly. At present, Addin Template does not get installed in Visual Studio 2008.

To get started with Visual C# and Visual Studio IDE (Integrated Development Environment), watch the following Videos from MSDN Library.

  1. Introduction to Visual C# 2008 Express Edition. Though we would be using Visual Studio 2005 for our development purpose, Visual C# Express Edition has similar functionality as Visual Studio. In this video, basic understanding of how an IDE works could be gained and also how C# programs and projects are developed and built.
  2. Introduction to C# Programming Language. This video shows how to develop C# applications using Visual Studio 2005. It is highly recommended that you download this package installer and upon installation on your system, you have a copy of Video downloaded and also a MS Word Document which is basically a transcript for the Video and also explains Basics of C# in a very good way.

I hope you also have downloaded DevTv: Introduction to Inventor Programming from Inventor Customization Page. In this video, Mr. Wayne Brill of Autodesk has explained API concepts very well, but they are either in VB6 or VB.NET. I would like to highlight to the audience that even in Inventor Programmers Help (Located in Help tab), most of the code examples are given in VB.NET or VBA.

I would try to bridge the gap by giving out equivalent C# code in the blog posts to follow. You may also be interested to check out a free VB.Net to VC# translator I stumbled upon, though I haven’t used it yet.