I have a Windows Forms app that is able to launch a console for debuggin. In the app, through a menu click, I read a CSV file and write it to the console. The function that does this is below.
protected void menuRead_Click(object sender, EventArgs e)
{
// ... functionality to load CSV files
System.IO.Stream inputDataFile = null;
OpenFileDialog fd = new OpenFileDialog();
fd.InitialDirectory = "c:\\";
fd.Filter = "csv files (*.csv)|*.csv|All files (*.*)|*.*";
fd.FilterIndex = 1;
fd.RestoreDirectory = true;
if (fd.ShowDialog() == DialogResult.OK)
{
try
{
if ((inputDataFile = fd.OpenFile()) != null)
{
inputData_exists = true;
// ... read input data from CSV file
using (CsvFileReader reader = new CsvFileReader(inputDataFile))
{
CsvRow row = new CsvRow();
while (reader.ReadRow(row))
{
foreach (string s in row)
{
Console.Write(s);
Console.Write(" ");
}
Console.WriteLine();
}
// ... close the input data stream
inputDataFile.Close();
}
}
}
catch (Exception err)
{
//Inform the user if can't read the file
MessageBox.Show(err.Message);
}
}
}
Everything works fine except the following:
The csv file has about 1200 lines of code. When this code is executed, the OpenFileDialog() window only closes partially before the csv file contents begin to get written to the console window. So, I can see the data writing to the console window, and I have a small rectangular portion of the dialog window showing on my form. Is there any way to ensure the dialog is closed before the data is written to the console? Should I open anew thread to communicate with the console? Any advise or help woulf be greatly appreciated. Thank you.
You need to give some time for your control "OpenFileDialog" to repaint itself during dispose of the control, the easiest way for WinForm is to use Application.DoEvents()
if (fd.ShowDialog() == DialogResult.OK)
{
Application.DoEvents();
...
...
}
Your issue comes from the fact you display the console and your ShowDialog call. Get the result of the of Dialog then open your console application. You can also read the file on another thread I suppose.
You may use a lot of approaches here.
The simplest one:
Use StringBuilder and than put all data at once.
Because output to console may be quite slowly.
StringBuilder consoleBuffer = new StringBuilder();
using (CsvFileReader reader = new CsvFileReader(inputDataFile))
{
CsvRow row = new CsvRow();
while (reader.ReadRow(row))
{
foreach (string s in row)
{
consoleBuffer.Append(s);
consoleBuffer.Append(" ");
}
consoleBuffer.Append(Environment.NewLine);
}
Console.WriteLine(consoleBuffer.ToString());
// ... close the input data stream
inputDataFile.Close();
}
Related
I am converting a .txt file to a pdf and need to display the pdf to the user. For that, I have created a temporary .pdf file and created a process to open the file. This works fine when there is adobe acrobat installed. This fails when there is no default application. For my case, the pdf is opened in internet explorer and I get No process is associated with this object exception. Is there any other way to find out when the file is being closed so that I can delete it later on.
My code is like this.
HtmlToPdf htmlToPdf = new HtmlToPdf(pdfPrintOptions);
string tmpFileName = "zx" + DateTime.Now.Ticks + "x.pdf";
//Iron pdf does not handle in-memory pdf viewing
//convert it to pdf
htmlToPdf.RenderHTMLFileAsPdf(fileWithPath).SaveAs(tmpFileName);
// TempFileCollection tmpFileCollection = new TempFileCollection();
//Use windows process to open the file
Process pdfViewerProcess = new Process
{
EnableRaisingEvents = true, StartInfo = {FileName = tmpFileName}
};
pdfViewerProcess.Start();
pdfViewerProcess.WaitForExit(); **Failing in this line**
//Delete temporary file after the viewing windows is closed
if (File.Exists(tmpFileName))
{
File.Delete(tmpFileName);
}
Similar questions do not seem to provide a workaround for this problem. Any help will be appreciated. Thanks.
You have to define tmpFileName in global variable and use Event Exited like this:
try{
Process myProcess = new Process();
myProcess.StartInfo.FileName = tmpFileName;
myProcess.EnableRaisingEvents = true;
myProcess.Exited += new EventHandler(myProcess_Exited);
myProcess.Start();
}
catch (Exception ex){
//Handle ERROR
return;
}
// Method Handle Exited event.
private void myProcess_Exited(object sender, System.EventArgs e){
if (File.Exists(tmpFileName))
{
File.Delete(tmpFileName);
}
}
Hope it can help you
Update my answers:
If it still not working. Try this answers
I would just save the PDF file in the TEMP folder.
Either in Windows User TEMP folder or your App can create a TEMP folder. If you create a TEMP folder just delete every file when your app closed.
string filePath = Path.GetTempPath() + "yourfile.pdf";
//Writer your file to Path
//File.WriteAllBytes(filePath, content);
Process.Start(filePath);
I'm pretty new to C# and I'm experimenting a lot, I'm trying to make my program a little more user friendly and that is where the problem starts.
At first the location of the excelfile was in a public static string and I had no problems. I've changed it to this:
public string Excellocation()
{
string xlLocation;
if (but_Browse.Text == "Zoek Excel")
{
xlLocation = #"E:\Levi\Documents\Verjaardagen.xlsx";
}
else //Only if I get into this part of my code I get the error
{
xlLocation = but_Browse.Text;
}
return xlLocation;
}
And the button I use so the user can give me a location for the excel file is:
private void but_Browse_Click(object sender, EventArgs e)
{
var FD = new System.Windows.Forms.OpenFileDialog();
if (FD.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
string fileToOpen = FD.FileName;
System.IO.FileInfo File = new System.IO.FileInfo(FD.FileName);
//OR
System.IO.StreamReader reader = new System.IO.StreamReader(fileToOpen);
//etc
but_Browse.Text = fileToOpen;
this.but_Browse.AutoSize = true;
But_Import.Visible = true;
}
}
Reading the Excel-file is no problem, my program finds it and processes it, if and only if the user changed the location by using the "Browse button" I get a message from Windows that there is already an excel file with that name and if I want to replace it, If I click away that message, my code gives an error on the line that tries to save the excel file
xlWorkbook.Save();
xlWorkbook.Close(true);
xlApp.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);
xlWorkbook.Save() gives me this error:
System.Runtime.InteropServices.COMException occurred
HResult=0x800A03EC Message=Verjaardagen.xlsx can not be saved,
because it's read-only.
I have no idea why I don't get an error with the default location while I do get an error if use my button to give me that same location.
Does anyone know what i'm doing wrong?
Thanks in advance
So the problem is that the file is read only when you try to write to it after going through but_Browse_Click? Are you closing the StreamReader? Try using
reader.close();
in but_Browse_Click.
Perhaps a better way would be:
using (StreamReader reader = new StreamReader(fileToOpen))
{
//all code involving the reader in here
}
This automatically closes on completion.
I want to use/read attached files from an outlook email into a WinForm solution.
Ex: the email has a TXT file attached; I want to perform a Drag&Drog of the TXT file into the WinForm and read the TXT at the same time.
This is an old question, but I'll provide another answer anyhow that doesn't involve using the Outlook objects.
This URL provides working code that is about 13 years old, but still seems to work, on how to handle the "FileGroupDescriptor" and "FileContents" data that Outlook passes to the DropDrop event. Just in case that link dies, here is the relevant code, copy/pasted directly:
DragEnter event:
private void Form1_DragEnter(object sender, System.Windows.Forms.DragEventArgs e)
{
// for this program, we allow a file to be dropped from Explorer
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{ e.Effect = DragDropEffects.Copy;}
// or this tells us if it is an Outlook attachment drop
else if (e.Data.GetDataPresent("FileGroupDescriptor"))
{ e.Effect = DragDropEffects.Copy;}
// or none of the above
else
{ e.Effect = DragDropEffects.None;}
}
DragDrop event:
private void Form1_DragDrop(object sender, System.Windows.Forms.DragEventArgs e)
{
string [] fileNames = null;
try
{
if ( e.Data.GetDataPresent(DataFormats.FileDrop,false) == true)
{
fileNames = (string []) e.Data.GetData(DataFormats.FileDrop);
// handle each file passed as needed
foreach( string fileName in fileNames)
{
// do what you are going to do with each filename
}
}
else if (e.Data.GetDataPresent("FileGroupDescriptor"))
{
//
// the first step here is to get the filename
// of the attachment and
// build a full-path name so we can store it
// in the temporary folder
//
// set up to obtain the FileGroupDescriptor
// and extract the file name
Stream theStream = (Stream) e.Data.GetData("FileGroupDescriptor");
byte [] fileGroupDescriptor = new byte[512];
theStream.Read(fileGroupDescriptor,0,512);
// used to build the filename from the FileGroupDescriptor block
StringBuilder fileName = new StringBuilder("");
// this trick gets the filename of the passed attached file
for(int i=76; fileGroupDescriptor[i]!=0; i++)
{ fileName.Append(Convert.ToChar(fileGroupDescriptor[i]));}
theStream.Close();
string path = Path.GetTempPath();
// put the zip file into the temp directory
string theFile = path+fileName.ToString();
// create the full-path name
//
// Second step: we have the file name.
// Now we need to get the actual raw
// data for the attached file and copy it to disk so we work on it.
//
// get the actual raw file into memory
MemoryStream ms = (MemoryStream) e.Data.GetData(
"FileContents",true);
// allocate enough bytes to hold the raw data
byte [] fileBytes = new byte[ms.Length];
// set starting position at first byte and read in the raw data
ms.Position = 0;
ms.Read(fileBytes,0,(int)ms.Length);
// create a file and save the raw zip file to it
FileStream fs = new FileStream(theFile,FileMode.Create);
fs.Write(fileBytes,0,(int)fileBytes.Length);
fs.Close(); // close the file
FileInfo tempFile = new FileInfo(theFile);
// always good to make sure we actually created the file
if ( tempFile.Exists == true)
{
// for now, just delete what we created
tempFile.Delete();
}
else
{ Trace.WriteLine("File was not created!");}
}
}
catch (Exception ex)
{
Trace.WriteLine("Error in DragDrop function: " + ex.Message);
// don't use MessageBox here - Outlook or Explorer is waiting !
}
}
Note that this code doesn't Dispose of objects that it should, such as the MemoryStream and FileStream objects.
You can get the running Outlook instance by using the GetActiveObject method which allows to obtain a running instance of the specified object from the running object table (ROT). Then you can automate Outlook to get the currently selected or opened item from which an attachment might be dragged. See C# app automates Outlook (CSAutomateOutlook) for the sample code.
I've been looking on many websites now for the answer, but all working answers only work for the richTextbox, and I'm using the normal textbox. I'm trying to save the contents of the textbox to a file of choice, but for some reason the file doesn't get saved, and I have no idea what the problem is. This is the code of the 'save' menu item:
private void saveToolStripMenuItem_Click(object sender, EventArgs e)
{
SaveFileDialog ofd = new SaveFileDialog();
ofd.Title = "Save";
ofd.Filter = "Txt Documents (.txt)|*.txt|All files (*.*)|*.*";
if (ofd.ShowDialog() == DialogResult.OK)
{
try
{
//I don't know what to make of this, because clearly this doesn't work
File.WriteAllText(#"./TestFile.txt", MainTextbox.Text);
}
catch (Exception ex)
{
MainTextbox.Text += ex;
}
}
}
There is no error.
You should be saving to the file selected in your SaveFileDialog, as retrieved by OpenFile(). This example worked for me:
SaveFileDialog ofd = new SaveFileDialog();
ofd.Title = "Save";
ofd.Filter = "Txt Documents (.txt)|*.txt|All files (*.*)|*.*";
if (ofd.ShowDialog() == DialogResult.OK)
{
using (var fileStream = ofd.OpenFile())
using (var sw = new StreamWriter(fileStream))
sw.WriteLine("Some text");
}
In your code, you let the user select a file to save to, then ignore that and write it to a hardcoded location. It's possible your app didn't have permissions to do this, but it should have permissions to write to a location the user selected.
First off, saving the file has nothing to do with where the text is coming from, rich text box or normal text box.
As Brian S. said in a comment, it is likely there is an exception because you're writing to the C drive. You should use a relative path: "./MyTest.txt"
I think its access denied issue.. try with 'D' drive ...
This is working example.. .WriteAllText works when file already exists and if file already exists then use AppendAllText
using System;
using System.IO;
using System.Text;
class Test
{
public static void Main()
{
string path = #"c:\temp\MyTest.txt";
// This text is added only once to the file.
if (!File.Exists(path))
{
// Create a file to write to.
string createText = "Hello and Welcome" + Environment.NewLine;
File.WriteAllText(path, createText);
}
// This text is always added, making the file longer over time
// if it is not deleted.
string appendText = "This is extra text" + Environment.NewLine;
File.AppendAllText(path, appendText);
// Open the file to read from.
string readText = File.ReadAllText(path);
Console.WriteLine(readText);
}
}
Use a try { } catch (Exception ex) { } block How to: Use the Try/Catch Block to Catch Exceptions
I want the users to type their text in the given textbox and on clicking on createNewFile Button, a SaveAs Dialogbox should popup and the users should browse through the location and save the file as desired.
I have tried some thing but
1. The dialog box goes behind the application
2. When run, dialogbox opens 3 times, means it executes 3 times
REPLY TO THE POST
protected void btnNewFile_Click(object sender, EventArgs e)
{
StreamWriter sw = null;
try
{
SaveFileDialog sdlg = new SaveFileDialog();
DialogResult result = sdlg.ShowDialog();
sdlg.InitialDirectory = #"C:\";
sdlg.AddExtension = true;
sdlg.CheckPathExists = true;
sdlg.CreatePrompt = false;
sdlg.OverwritePrompt = true;
sdlg.ValidateNames = true;
sdlg.ShowHelp = true;
sdlg.DefaultExt = "txt";
string file = sdlg.FileName.ToString();
string data = txtNewFile.Text;
if (sdlg.ShowDialog() == DialogResult.OK)
{
sw.WriteLine(txtNewFile.Text);
sw.Close();
}
if (sdlg.ShowDialog() == DialogResult.Cancel)
{ sw.Dispose(); }
}
catch
{ }
finally
{
if (sw != null)
{
sw.Close();
}
}
}
private void Save(string file, string data)
{
StreamWriter writer = new StreamWriter(file);
SaveFileDialog sdlg1 = new SaveFileDialog();
try
{
if (sdlg1.ShowDialog() == DialogResult.OK)
{
writer.Write(data);
writer.Close();
}
else
writer.Dispose();
}
catch (Exception xp)
{
MessageBox.Show(xp.Message);
}
finally
{
if (writer != null)
{
writer.Close();
}
}
}
I have tried this.
The SaveFileDialog is a windows forms control, it doesn't work on a website.
A browser will display the "What do you want to do with this file" dialog whenever a server sends it a stream it can't handle by default - unfortunately, most browsers can handle text streams, so will just display them to the user.
But something like this should get you going:
protected void btnNewFile_Click(object sender, EventArgs e)
{
// Clear the response buffer:
Response.Clear();
// Set the output to plain text:
Response.ContentType = "text/plain";
// Send the contents of the textbox to the output stream:
Response.Write(txtNewFile.Text);
// End the response so we don't get anything else sent (page furniture etc):
Response.End();
}
But as I said, most browsers can cope with plain text, so you might need to lie to the browser and pass in a application type, but then that might limit the usefulness of the download on some machines.
As others have said, you can't use the SaveFileDialog. If you do, it will only be visible on the server, and the user can never see it. You can only see it because in your case the server and the client happen to be the same.
You should set the HTTP header
Content-Disposition: attachment; filename=somefilename.txt
I assume you are trying this in Winforms env.
The issue here is you are issuing three calls to .ShowDialog in your code which pops the dialog three times. You just need to call ShowDialog once and then save and use the result onlyas below
DialogResult result = sdlg.ShowDialog();
if (result == DialogResult.OK)
{
sw.WriteLine(data);
sw.Close();
}
else if (result == DialogResult.Cancel)
{
}
There is no SaveAs Dialogbox in ASP.NET. But you can force your application to generate a file on the server and have it sent back to the user.
string userProvidedText = uiTextBox.Text; // this is your textbox
byte[] userProvidedTextAsBytes = null;
if (!string.IsNullOrEmpty(userProvidedText )) {
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
userProvidedTextAsBytes = encoding.GetBytes(userProvidedText);
}
Response.AppendHeader("Content-Disposition", "attachment; filename=YourFileName.html");
Response.ContentType = "text/HTML";
Response.BinaryWrite(userProvidedTextAsBytes);
Response.End();
When this code runs, the applications generates "on the fly" YourFileName.html and returns it to the user. At this point the Browser intercepts the resulting output and ask the user what to do with that specific file.
alt text http://www.cyphersec.com/wp-content/uploads/2009/04/output1.png
Note: Use Response.TransmitFile() if you want to serve previously stored files. The reason behind it is that TransmitFile is very efficent because it basically offloads the file streaming to IIS including potentially causing the file to get cached in the Kernel (base on IIS’s caching rules).