Write to CSV with button. Used for Bartender

Refactoring tool for our Italian coder?

[cid:image001.jpg@01D29F33.A97521A0]

3 Likes

OK, so I am working on trying to get this to work. (remember I know veeerrryy little about coding and C# in general). For the first step I just wanted to get a file to pop out. I didn’t care what was in it, just get something to go where I wanted with something in it. I figured that out (although it’s embarrassing how long it took) . So here is the code for that.

	string test = "test";
	System.IO.File.WriteAllText("network location and file name",test);

That go plugged into the event wizard and it created this

private static void epiButton1_Click(object sender, System.EventArgs args)
{
	
	string test = "test";
	System.IO.File.WriteAllText("\network location and file name",test);
	
}

So I was able to figure out the first part of simple making a button do something.

Now I get stuck because I don’t know how exactly to get the data defined. I took your start with the MakeLabelData and shortened it to only part number and description (for example if I just want to make a part label) But I’m not sure where to put that. I’m assuming that you put a private void (that’s like a mini program right?) in front of the event call so that you can use the program within the button click?

It’s looking to me like something even this simple might be past my ability level, I don’t know the bare bones basics that I need to know about C#…

1 Like

Copy your code and attach as a text file here, then list all of the
relevant controls and their guids and I’ll do it up for you

So, This is where the problem begins, when you say list all of the relevant controls and and guids, I sort of know what you are talking about, but not enough to effectively give you what you need. So let’s try this. I created a very simple dashboard with a query that lists all of the parts in the part master and a tracker view with a few simple filters. It’s all stock stuff so it should work in any system. I created the button and the event handler wizard to get to the point where I would start putting in code. (This is where I get stuck, because I don’t know enough about C# to know the basic set up procedures to even get to the googling code pieces to copy and paste in.) All I want is to be able to select a row, or some rows, and the selected information (and the column headers) be populated in a csv and dropped into a folder somewhere on the network. I don’t need to control any printers at this point, or create the BT control header because I will just set all of that up in the integration builder via bartender. The end goal here is to make something that is as simple as possible so that I can learn basic setup and be able to build on this example, although even this simple tool here would save a lot of time to print labels more easily.

PrintLabelTest.dbd (106.7 KB)

And if you don’t have time or want to do this for me, I totally understand. You have definitely already gone above and beyond. Hopefully this starting point will help a lot of other people besides just me and my company.

Thanks,
Brandon

I’m glad you sent me the file so I could see your confusion. I guess I’ve never written custom code on top of a dashboard. I am not even sure how we reference the grid object in this case lol. We’ll figure it out - I need to learn how as well.

In the meantime:

I’ll give you a couple general pointers
private void MakeLabelData(string pn, string desc)
{

}

private means that this function cant be seen outside of this file.
void is the return type (we aren’t returning anything here)
pn and desc are parameters being passed into the function, both are of type string (text)
The { and } denote the start and end of the function. Notice there are other ‘groupings’ of text that use { } as well but they always come in pairs.

In your error above, I believe your problem is your dashboard is defined as static. I’ll avoid trying to go into what all of that means but suffice it to say you can compile by changing the function definition to:
private static void MakeLabelData (string pn, string desc)

Also we have to make our global vars static.

Ok I’ve figured it out. You have to deploy your dashboard as an assembly, Add it to you menu, then you can customize it proper.

The only catches I saw was that I had to access the button you created as a system control (using csm.GetaNativeControlReference) which means you can NOT use the wizard to create the onClick event.

I’ve done that manually.Once you deploy your DB as assembly and open customization, you can use this as a guide. NOTE your GUID’s are probably going to be different for your grid and button but you can get those from the properties tab.

// Created: 3/20/2017 9:31:22 AM
// **************************************************
using System;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Windows.Forms;
using Ice.BO;
using Ice.UI;
using Ice.Lib;
using Ice.Adapters;
using Ice.Lib.Customization;
using Ice.Lib.ExtendedProps;
using Ice.Lib.Framework;
using Ice.Lib.Searches;
using Ice.UI.FormFunctions;

public class Script
{
	// ** Wizard Insert Location - Do Not Remove 'Begin/End Wizard Added Module Level Variables' Comments! **
	// Begin Wizard Added Module Level Variables **

	// End Wizard Added Module Level Variables **

	// Add Custom Module Level Variables Here **
EpiUltraGrid LabelGrid;
EpiButton PrintButton;
string datas;
string headers;
string myCSV;

	public void InitializeCustomCode()
	{
		// ** Wizard Insert Location - Do not delete 'Begin/End Wizard Added Variable Initialization' lines **
		// Begin Wizard Added Variable Initialization

		// End Wizard Added Variable Initialization

		// Begin Wizard Added Custom Method Calls

		// End Wizard Added Custom Method Calls

 		LabelGrid = (EpiUltraGrid)csm.GetNativeControlReference("8d6c1c8e-c9b5-46f6-b859-4895c6c990ea");
		 PrintButton = (EpiButton)csm.GetNativeControlReference("312c5ff2-89c0-48ac-94ec-b2ec1dfdbf36");

			PrintButton.Click += new EventHandler(PrintClick);
	}

	public void DestroyCustomCode()
	{
		// ** Wizard Insert Location - Do not delete 'Begin/End Wizard Added Object Disposal' lines **
		// Begin Wizard Added Object Disposal

		// End Wizard Added Object Disposal

		// Begin Custom Code Disposal

		// End Custom Code Disposal
			PrintButton.Click -= new EventHandler(PrintClick);
	}

    private void MakeLabelData(string pn, string desc)
	{
		this.headers = string.Format("\"{0}\",\"{1}\"", new object[]
		{
			"pn",
			"desc"
		});
        this.datas = string.Format("\"{0}\",\"{1}\"", new object[]
		{
			pn,
			desc
		});
	}

	private void PrintClick(object sender, EventArgs e)
	{
		string to = "\\\\Server\\Folder\\junk.txt";
                string[] source = {""};


		myCSV = ""; //make sure our CSV is empty
		foreach(var row in LabelGrid.Rows)   //.the var row now represents the current row as we iterate
		{
		   if(row.Selected)// for only selected rows
		   {
		    addDataToCSV(row.Cells["Part_PartNum"].Value.ToString());                          
		    addDataToCSV(row.Cells["Part_PartDescription"].Value.ToString());                          
		    
		
		   }
		}
	
		MessageBox.Show("CSV: " + myCSV);
		source[0] = myCSV;
		System.IO.File.WriteAllLines(to,source);
        
	}

		private void addDataToCSV(string datastring)
        {
            if (myCSV.Length > 0) myCSV += ",";
            myCSV += "\"" + datastring + "\"";
        }

}
2 Likes

Alright, I’ll have to try it later. I’ll have to get customization privaledges turned on. Generally our strategy so far has been to stay away from customizations if we can so we make sure any upgrade will be easier. This doesn’t really apply since it’s to a custom dashboard, but that’s one of the reasons that I haven’t had that turned on for me (along with the fact that I don’t know what I’m doing, but that’s beside the point. :wink:.)

Do I want that whole line in there? Or should I shorten that to just pn and desc?

I’m sure I’ll have more questions, but that was the first thing that I saw that seemed a little odd.

And to reiterate, the things that I should be changing to my system would be the 2 guids, (one for the button and one for the grid), and the network location for the drop. Right?

Sure enough, I missed that. Remove all but your string pn and string desc parameters. (I updated the code)

You are correct, that should get it going <fingers crossed >

I would point out that your BAQ has the PN limited - that may be on purpose but for my testing I had to remove it since I didn’t have any matching pn’s

Perfect,

Yeah, I forgot about the filter. That was just to reduce the number of records returned. I’ll be taking that out.

Thanks, I let you know how it goes when I get a chance to try it.

Brandon

2 Likes

So. I got the button working. SUPER excited. There are a couple of changes needed.

First, the headers are in the file. In the private void PrintClick(object sender, EventArgs e) section, we need to call the header to be sent somewhere right?

Secondly, there needs to be a carriage return after the lines. The text file has all one line. I’m thinking, after the addDataToCSV line of the code below, there should be something to add the carriage return right?

myCSV = ""; //make sure our CSV is empty
		foreach(var row in LabelGrid.Rows)   //.the var row now represents the current row as we iterate
		{
		   if(row.Selected)// for only selected rows
		   {
		    addDataToCSV(row.Cells["Part_PartNum"].Value.ToString());                          
		    addDataToCSV(row.Cells["Part_PartDescription"].Value.ToString());                          
		    
		
		   }
		}

Other than those 2 little things it works great. I’m super excited to get this working.

So I did some googling and tried adding this code

It puts quotes around the carriage return (big surprise right.)

I’ve been trying to find out how to get the header data to write first, but no luck yet.

Sorry for the delay - super busy today. Glad it got going.

Maybe the easiest way is to do:

	private void addDataToCSV(string datastring)
        {
                  myCSV += datastring;
        }

What do we need to do with the headers? Do you need them or no? I apparently had a lapse of consciousness when I added MakeLabelData because we aren’t even using it.

The easiest way to ADD headers:

myCSV = ""; //make sure our CSV is empty
		foreach(var row in LabelGrid.Rows)   //.the var row now represents the current row as we iterate
		{
		    addDataToCSV("\"PartNumber\",");                           //ADDED
		    addDataToCSV("\"Description\"");                          //ADDED
     	            addDataToCSV(Environment.NewLine);   		 

		   if(row.Selected)// for only selected rows
		   {
		    addDataToCSV("\""+row.Cells["Part_PartNum"].Value.ToString()+"\",");                          
		    addDataToCSV(row.Cells["Part_PartDescription"].Value.ToString());                          
		    addDataToCSV(Environment.NewLine);   		    
		
		   }
		}
	
1 Like

Hey, I’m getting back into this stuff now. Lots of other stuff to catch up on. For headers, I needed the column headers. Maybe you caught when I said I didn’t need the Bartender headers (this line that starts and stops with %) because I was going to have the integration builder handle that for me. I was already trying what you said before you posted that.

I feel pretty dumb but it took me a few hours to figure out that the addDataToCSV was a private void written in this program, I kept thinking that it was something that was built in because I kept looking above instead of below. For stupid. Once I figured that out, it made sense what you were doing with adding the quotes around stuff, and why it would add the quotes around the carriage line. Then I moved around the headers so it only added those once instead of on every line. I added the quotes around the part description because it needed it there. I also moved the carriage line to the beginning of the data insert so I don’t get an extra line at the end of the CSV (I think that would lead to blank labels). When I do that I only need it in there once. Here’s my final code. This should work great. Thanks again for your help on this. I learned a ton and there is a lot of places where I can use this in our system.

  public class Script
{
	// ** Wizard Insert Location - Do Not Remove 'Begin/End Wizard Added Module Level Variables' Comments! **
	// Begin Wizard Added Module Level Variables **

	// End Wizard Added Module Level Variables **

	// Add Custom Module Level Variables Here **
EpiUltraGrid LabelGrid;
EpiButton PrintButton;
string datas;
string headers;
string myCSV;

	public void InitializeCustomCode()

	{
		// ** Wizard Insert Location - Do not delete 'Begin/End Wizard Added Variable Initialization' lines **
		// Begin Wizard Added Variable Initialization

		// End Wizard Added Variable Initialization

		// Begin Wizard Added Custom Method Calls

		// End Wizard Added Custom Method Calls

 		LabelGrid = (EpiUltraGrid)csm.GetNativeControlReference("8d6c1c8e-c9b5-46f6-b859-4895c6c990ea");
		 PrintButton = (EpiButton)csm.GetNativeControlReference("b5582d1a-df22-4cbb-8164-cda59df2654e");

			PrintButton.Click += new EventHandler(PrintClick);
	}

	public void DestroyCustomCode()
	{
		// ** Wizard Insert Location - Do not delete 'Begin/End Wizard Added Object Disposal' lines **
		// Begin Wizard Added Object Disposal

		// End Wizard Added Object Disposal

		// Begin Custom Code Disposal

		// End Custom Code Disposal
			PrintButton.Click -= new EventHandler(PrintClick);
	}

	private void PrintClick(object sender, EventArgs e)
	{
		string to = "\\\\network location\\clicktext.txt";
                string[] source = {""};


		myCSV = ""; //make sure our CSV is empty
			addDataToCSV("\"pn\","); //add the header information here. This can be done in one line or in many like is shown
			addDataToCSV("\"desc\"");
		foreach(var row in LabelGrid.Rows)   //.the var row now represents the current row as we iterate
		{
		   if(row.Selected)// for only selected rows
		   {

			addDataToCSV(Environment.NewLine);//this adds a carriage return to add this to the next line
		    addDataToCSV("\""+row.Cells["Part_PartNum"].Value.ToString()+"\","); //this adds the data with a comma after it. The comma is needed for each record except the last on a line  
		    addDataToCSV("\""+row.Cells["Part_PartDescription"].Value.ToString()+"\""); //this is the last record on the line. It doesn't need a comma becuase there will be a carriage return before the next line
		   }
		}
	
		MessageBox.Show("CSV: " + myCSV);
		source[0] = myCSV;
		System.IO.File.WriteAllLines(to,source);
        
	}

		private void addDataToCSV(string datastring)
        {
            myCSV += datastring ;
        }

}
1 Like

Awesome, glad you got it! I’ll catch you at Insights.

1 Like

Question about some code basics. Below is the destroy custom code section. So I took what I learned here and duplicated/expanded it to another dashboard where there are three different places where I used a button. So everything got triplicated with the appropriate pieces changed out. Seems to work fine. One of the things that I forgot to triplicate was the destroy custom code section (I fixed it once I noticed it). My question is, what kind of bad things could happen if I were to miss that piece of setup?

Best case scenario, nothing since the objects we hooked those events to are gone. Worse case scenario, memory leak. This means that you aren’t freeing up things you created and over time they keep building up, causing issues eventually.

In this instance, I am pretty sure that C# garbage collection takes care of it since the object is destroyed when that form is closed anyway.

Good to know.

Depending on the object and the event you could be leaving a registered event listener and create a memory leak. Always be a good citizen and dispose of your objects (specially de-register all events)

2 Likes