Referencing StreamReader in two methods - c#

Quite new to OO so please be kind.
I have created a method which when button1 is clicked, opens a file dialog and reads the contents into a stream reader sr;
public void button1_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
label1.Text = openFileDialog1.FileName;
StreamReader sr = new StreamReader(label1.Text);
String strNumVertices = sr.ReadLine();
label2.Text = strNumVertices;
}
}
The other code runs in the Form1_Paint method.
public void Form1_Paint(object sender, PaintEventArgs e)
perspectiveMatrix = new Gmatrix("perspective");
translationMatrix = new Gmatrix("translation");
scalingMatrix = new Gmatrix("scaling");
perspectiveMatrix.initAsPerspectiveMatrix(300);
scalingMatrix.initAsScalingMatrix(10, 10, 10);
translationMatrix.initAsTranslationMatrix(150, 50, 1200);
String strNumVertices = sr.ReadLine();
label1.Text = strNumVertices;
My question is, How do I reference stream reader sr from the button1_click method in the Form1_paint method?

Word of advice - don't try.
If you do so, you are in danger of having open files/streams all over the place.
I suggest you open a new steam reader in each method (or abstract it away into its own method).
Note:
You should be wrapping the opening of the stream in a using statement, to ensure proper disposal:
using(StreamReader sr = new StreamReader(label1.Text))
{
String strNumVertices = sr.ReadLine();
label2.Text = strNumVertices;
}

Actually, it should be not the best idea to read from the stream during each paint run. Perhaps you'd like to read the value once, store it in the member variable of your form, and access in the paint method?

Unless you expect the file to have changed between the button click and the paint method being called then you shouldn't be reading from the file again anyway.
Reading the file is very expensive in terms of performance compared to storing the result in a field and retreiving it during the paint method. Or visa versa depending what executes first.

Make it a field on the form class. This changes the scope from the method to the entire form. The warnings from the previous post are still valid.
StreamReader sr;
public void button1_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
label1.Text = openFileDialog1.FileName;
sr = new StreamReader(label1.Text);
String strNumVertices = sr.ReadLine();
label2.Text = strNumVertices;
}
}
public void Form1_Paint(object sender, PaintEventArgs e)
perspectiveMatrix = new Gmatrix("perspective");
translationMatrix = new Gmatrix("translation");
scalingMatrix = new Gmatrix("scaling");
perspectiveMatrix.initAsPerspectiveMatrix(300);
scalingMatrix.initAsScalingMatrix(10, 10, 10);
translationMatrix.initAsTranslationMatrix(150, 50, 1200);
if (sr != null) {
String strNumVertices = sr.ReadLine();
label1.Text = strNumVertices;
}

Why not just store the data you've read from the file and re-use it rather than reading the file again? I'm assuming these methods are in the same class (and the same instance of the object), but there are ways around that if that's not true.
private string StrNumVertices { get; set; }
public void button1_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
label1.Text = openFileDialog1.FileName;
StreamReader sr = new StreamReader(label1.Text);
this.StrNumVertices = sr.ReadLine();
label2.Text = this.StrNumVertices;
}
}
public void Form1_Paint(object sender, PaintEventArgs e)
perspectiveMatrix = new Gmatrix("perspective");
translationMatrix = new Gmatrix("translation");
scalingMatrix = new Gmatrix("scaling");
perspectiveMatrix.initAsPerspectiveMatrix(300);
scalingMatrix.initAsScalingMatrix(10, 10, 10);
translationMatrix.initAsTranslationMatrix(150, 50, 1200);
label1.Text = this.StrNumVertices;
...
}
If it's not the same instance of the object, then I'd consider using a Singleton configuration object (or cache) and storing the data there. It really depends, of course, on the scope and lifetime of the data -- does it apply to the whole application or just this instance? The best way, of course, is to make it an instance property like above, and I assume this will work, but if you're recreating the object you will have to use a different technique.
If you really do want to read the file again (because the data is from a different line), you will need to re-use the stream or, again, read all of the data in one go -- if possible -- then iterate through the items you've read internally.

Related

c# / Rename dll using OpenFileDialog

i'm stuck with my program in c#. So the user has to press a button to create a random string (working fine) he can then chose to click on the other button. this one opens a filedialog and let him chose a dll file he want to rename into the random string. i can't get it working. it says my dll is already running in another process (wich is not). Any help is greatly appreciated :)
private void btnEncrypt_Click_1(object sender, EventArgs e)
{
// sets a random string to txtEncrypt.text
}
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog MyOpenFileDialog = new OpenFileDialog();
//filedialog
MyOpenFileDialog.Filter = "dll files (*.dll) |*.dll";//filter
MyOpenFileDialog.Title = "Chose the dll file";
MyOpenFileDialog.InitialDirectory = "C:\\Users\\Gebruiker\\Desktop";
MyOpenFileDialog.FilterIndex = 1;
MyOpenFileDialog.RestoreDirectory = true;
//if ok
if (MyOpenFileDialog.ShowDialog() == DialogResult.OK)
{
strPath = MyOpenFileDialog.FileName;
StreamReader reader = new StreamReader(strPath);
System.IO.File.Move(strPath, "C:\\Users\\Gebruiker\\Desktop\\" + txtEncrypt.Text + ".dll");
}
else //cancel
{
strPath = null;
}
It's because your StreamReader is opening the file so it can't be moved. That line doesn't appear to be doing anything anyway so you can probably remove it. Ideally replace it with
if (System.IO.File.Exists(strPath))
{
System.IO.File.Move(strPath, "C:\\Users\\Gebruiker\\Desktop\\" + txtEncrypt.Text + ".dll");
}
Just comment the initialization of the streem reader line or move it next to the rename line but don't forget to pass the new name

Creating a text file with user entered name using c#

hi i have a webform where i am trying to create a txt file in a particular directory but i want to the name of the txt file to be entered by the user but I am not getting it how to do it please help
the code below creates a text file with name NameBox.Text.ToString I dont want that please help and thanks.
protected void Page_Load(object sender, EventArgs e)
{
NameLabel.Visible = false;
NameBox.Visible = false;
submit.Visible = false;
}
protected void Button1_Click(object sender, EventArgs e)
{
NameLabel.Visible = true;
NameBox.Visible = true;
submit.Visible = true;
}
protected void submit_Click(object sender, EventArgs e)
{
// string fname = NameBox.Text;
string path = #"D:\NameBox.Text.ToString.txt";
try
{
// Delete the file if it exists.
if (File.Exists(path))
{
// Note that no lock is put on the
// file and the possibility exists
// that another process could do
// something with it between
// the calls to Exists and Delete.
File.Delete(path);
}
// Create the file.
using (FileStream fs = File.Create(path))
{
Byte[] info = new UTF8Encoding(true).GetBytes("This is some text in the file.");
// Add some information to the file.
fs.Write(info, 0, info.Length);
}
// Open the stream and read it back.
using (StreamReader sr = File.OpenText(path))
{
string s = "";
while ((s = sr.ReadLine()) != null)
{
Console.WriteLine(s);
}
}
}
catch (Exception Ex)
{
Console.WriteLine(Ex.ToString());
}
}
}
First, keep in mind that your IIS will not allow you to access your local file System as you expcect in a "console" application, maybe running with local admin rights.
Second, be sware of illegal characters for file names, you need to check or replace it.
And third, what if two users decide to use the same filename?
As Dejan Dakic already mentioned, step back and reconsider, maybe about using a database, like SQLite or something else.
string path = #"D:\NameBox.Text.ToString.txt";
That won't work. if your textfield is called "NameBox" you need to access the value of its text which is not possible within a String.
Try this:
String path = #"D:\" + NameBox.Text + ".txt";
If you're new to programming, I'd suggest to go get a book or some tutorials and get started that way! :)

how do I recall a string from a different function?

I am having trouble calling the string "rlist" from:
public void main()
{
string rlist;
if (radioButton1.Checked)
textBox1.Enabled = false;
textBox1.ReadOnly = true;
rlist = "text";
}
to
public void button1_Click(object sender, EventArgs e)
{
OpenFileDialog openFile = new OpenFileDialog();
openFile.Filter = "WTF Files (*.wtf)|*.wtf";
openFile.Title = "Please Pick your realmlist file:";
if (openFile.ShowDialog() == DialogResult.Cancel)
return;
try
{
textBox5.Text = openFile.FileName;
string file = openFile.FileName;
TextWriter rlist_writer = new StreamWriter (openFile.FileName);
rlist_writer.WriteLine(rlist);
rlist_writer.Close();
}
catch (Exception)
{
MessageBox.Show("Error opening file", "File Error",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
I get the error on this line:
rlist_writer.WriteLine(rlist);
is it possible to call a string from one function and send it to the other with the same value it had in the function it was originally pulled from?
By the sounds of your question,
Your string is local to your main function.
So judging by your method names and knowledge of winforms(presumed again)
you need to make your string class level
string rlist;
public void main()
{
rlist = "yay"
public void button1_Click(object sender, EventArgs e)
{
someText = rlist;
As it currently stands you are not able to, as temporary (local) variables will be cleaned through garbage collection when you leave the method
Edit
You may wish to review this also
try
{
textBox5.Text = openFile.FileName;
using(TextWriter rlist_writer = new StreamWriter (openFile.FileName))
{
rlist_writer.WriteLine(rlist);
}
}
You can define that variable in your class scope, then if you call that variable in your button_click event, it will maintain the same value as in your main method.

C# ListBox Import from Text File Crash

I am using this code to import text file to my ListBox
OpenFileDialog openFileDialog1 = new OpenFileDialog();
openFileDialog1.Filter = "Text Files|*.txt";
openFileDialog1.Title = "Select a Text file";
openFileDialog1.FileName = "";
DialogResult result = openFileDialog1.ShowDialog();
if (result == DialogResult.OK)
{
string file = openFileDialog1.FileName;
string[] text = System.IO.File.ReadAllLines(file);
foreach (string line in text)
{
listBox2.Items.Add(line);
}
listBox2.Items.Add("");
}
It works fine for small text files, with 10 lines or so, but when I try to import bigger list, (4-5 megabytes) the program isn't responding and it's crashing.
Any help?
Use the BufferedStream class in C# to improve performance.
http://msdn.microsoft.com/en-us/library/system.io.bufferedstream.aspx
By using this:
string[] text = System.IO.File.ReadAllLines(file);
listBox1.Items.AddRange(text);
instead of this:
string[] text = System.IO.File.ReadAllLines(file);
foreach (string line in text)
{
listBox2.Items.Add(line);
}
you will speed up the execution at least 10-15 times because you are not invalidating listBox on every Item insert.
I have measured with few thousand lines.
The bottleneck could also be ReadAllLines if your text has too many lines. Even though I can't figure out why you would be inserting so many lines, will user be able to find the line he/she needs?
EDIT OK then I suggest you to use BackgroundWorker, here is the code:
First you initialize BackGroundWorker:
BackgroundWorker bgw;
public Form1()
{
InitializeComponent();
bgw = new BackgroundWorker();
bgw.DoWork += new DoWorkEventHandler(bgw_DoWork);
bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgw_RunWorkerCompleted);
}
Then you call it in your method:
private void button1_Click(object sender, EventArgs e)
{
if (!bgw.IsBusy)
{
OpenFileDialog openFileDialog1 = new OpenFileDialog();
openFileDialog1.Filter = "Text Files|*.txt";
openFileDialog1.Title = "Select a Text file";
openFileDialog1.FileName = "";
DialogResult result = openFileDialog1.ShowDialog();
if (result == DialogResult.OK)
{
string file = openFileDialog1.FileName;
listView1.BeginUpdate();
bgw.RunWorkerAsync(file);
}
}
else
MessageBox.Show("File reading at the moment, try later!");
}
void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
listView1.EndUpdate();
}
void bgw_DoWork(object sender, DoWorkEventArgs e)
{
string fileName = (string)e.Argument;
TextReader t = new StreamReader(fileName);
string line = string.Empty;
while ((line = t.ReadLine()) != null)
{
string nLine = line;
this.Invoke((MethodInvoker)delegate { listBox1.Items.Add(nLine); });
}
}
It will add each line when it reads it, you will have responsive UI, and lines won't affect the listBox before it finishes loading.
It maybe simply not completing its job, and you should have to wait for more. Try with this solution:
http://www.bytechaser.com/en/articles/f3a3niqyb7/display-large-lists-in-listview-control-quickly.aspx
could use a stream to store the data:
class Test
{
public static void Main()
{
string path = #"c:\temp\MyTest.txt";
//Create the file.
using (FileStream fs = File.Create(path))
{
AddText(fs, "This is some text");
AddText(fs, "This is some more text,");
AddText(fs, "\r\nand this is on a new line");
AddText(fs, "\r\n\r\nThe following is a subset of characters:\r\n");
for (int i=1;i < 120;i++)
{
AddText(fs, Convert.ToChar(i).ToString());
}
}
//Open the stream and read it back.
using (FileStream fs = File.OpenRead(path))
{
byte[] b = new byte[1024];
UTF8Encoding temp = new UTF8Encoding(true);
while (fs.Read(b,0,b.Length) > 0)
{
Console.WriteLine(temp.GetString(b));
}
}
}
private static void AddText(FileStream fs, string value)
{
byte[] info = new UTF8Encoding(true).GetBytes(value);
fs.Write(info, 0, info.Length);
}
}
then you event handler
privateasyncvoid Button_Click(object sender, RoutedEventArgs e)
{
UnicodeEncoding uniencoding = new UnicodeEncoding();
string filename = #"c:\Users\exampleuser\Documents\userinputlog.txt";
byte[] result = uniencoding.GetBytes(UserInput.Text);
using (FileStream SourceStream = File.Open(filename, FileMode.OpenOrCreate))
{
SourceStream.Seek(0, SeekOrigin.End);
await SourceStream.WriteAsync(result, 0, result.Length);
}
}
Your application becomes unresponsive because it's waiting for the ReadAllLines method to complete and blocks the UI thread. You may want to read files on a separate thread to avoid blocking the UI. I cannot guarantee that the code below will work without errors but it should give you an idea on how to tackle the problem.
First of all, you'll need a method to append an item to the ListBox:
private void AddListBoxItem(string item)
{
if(!InvokeRequired)
{
listBox2.Items.Add(item);
}
else
{
var callback = new Action<string>(AddListBoxItem);
Invoke(callback, new object[]{item});
}
}
The method above checks if it is executed on UI thread and if yes, it simply adds an item to the listBox2.Items collection; if not, it creates a delegate from itself and invokes that delegate on UI thread.
Next, you'll need to move the code that reads the file to another thread and call AddListBoxItem method. For the sake of readability, let's put that into a separate method:
private void AddFileContentsToList(string fileName)
{
using(var reader = new System.IO.StreamReader(fileName))
{
while(!reader.EndOfStream)
{
var line = reader.ReadLine();
AddListBoxItem(line);
}
}
}
And now we will call the method on a separate thread:
OpenFileDialog openFileDialog1 = new OpenFileDialog();
openFileDialog1.Filter = "Text Files|*.txt";
openFileDialog1.Title = "Select a Text file";
openFileDialog1.FileName = "";
DialogResult result = openFileDialog1.ShowDialog();
if (result == DialogResult.OK)
{
var thread = new Thread(AddFileContentsToList);
thread.Start();
}
Hope this helps!

confused about implementing class into xml serialization

I was reading a book on serialization. I am confused about implementing class portion or simply put i don't really understand classes(maybe).
Basically i have my application designed in this way following the steps of my book. I just dont understand the class of FileSaving and maybe where to implement it. I would like to start using serialization to save elements of a form and reloading it via xml using a "Save" and "Load" button. I have a textbox and users keys in strings into the Majorversiontextbox and this textbox.text is then stored as MajorversionLabel. Please clarify my doubts and help me out with serialization. Thanks! I will clarify any doubts about my question.
EDIT
Question 1, Why do i need to have this FileSaving class when I am only getting values from the content from the label and saving it into a xml file. Question 2, is my FileSaving class declared correctly? Question 3, why do i need Get and Set over here?
public partial class Window1 : Window
{
...
...
public class FileSaving
{
private string major;
public string Majorversion
{
get
{
return major;
}
set
{
major = value;
}
}
}
private void MajorversionupdateButton_Click(object sender, RoutedEventArgs e)
{
MajorversionresultLabel.Content = MajorversionTextBox.Text;
MajorversionupdateButton.Visibility = Visibility.Hidden;
MajorversionTextBox.Visibility = Visibility.Hidden;
MajorversionmodifyButton.Visibility = Visibility.Visible;
}
private void SaveButton_Click(object sender, RoutedEventArgs e)
{
string savepath;
SaveFileDialog DialogSave = new SaveFileDialog();
// Default file extension
DialogSave.DefaultExt = "txt";
// Available file extensions
DialogSave.Filter = "XML file (*.xml)|*.xml|All files (*.*)|*.*";
// Adds a extension if the user does not
DialogSave.AddExtension = true;
// Restores the selected directory, next time
DialogSave.RestoreDirectory = true;
// Dialog title
DialogSave.Title = "Where do you want to save the file?";
// Startup directory
DialogSave.InitialDirectory = #"C:/";
DialogSave.ShowDialog();
savepath = DialogSave.FileName;
DialogSave.Dispose();
DialogSave = null;
Filesaving abc = new FileSaving();
abc.Majorversion = MajorversionLabel.Content;
FileStream savestream = new FileStream(path, FileMode.Create);
XmlSerializer serializer = new XmlSerializer(typeof(FileSaving));
serializer.Serialize(savestream, abc);
}
private void LoadButton_Click(object sender, RoutedEventArgs e)
{
string loadpath;
Stream checkStream = null;
Microsoft.Win32.OpenFileDialog DialogLoad = new Microsoft.Win32.OpenFileDialog();
DialogLoad.Multiselect = false;
DialogLoad.Filter = "XML file (*.xml)|*.xml|All files (*.*)|*.*";
if ((bool)DialogLoad.ShowDialog())
{
try
{
if ((checkStream = DialogLoad.OpenFile()) != null)
{
loadpath = DialogLoad.FileName;
}
}
catch (Exception ex)
{
System.Windows.MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
}
}
else
{
System.Windows.MessageBox.Show("Problem occured, try again later");
}
FileSaving abc = new FileSaving();
FileStream loadstream = new FileStream(loadpath, FileMode.Open);
XmlSerializer serializer = new XmlSerializer(typeof(FileSaving));
abc=(FileSaving)serializer.Deserialize(loadstream);
loadstream.Close();
MajorversionresultLabel.Content = abc.Majorversion;
}
}
because XmlSerializer is an object serializer, and works from the type definition
sure, that'll work
strictly speaking you don't, but the current version looks fine; XmlSerializer works for public properties or fields; you could simplify to an automatically-implemented property though: public string MajorVersion {get;set;}
But if you only want to save a single string value - is xml overfkill? File.WriteAllText / File.ReadAllText may be simpler.

Categories

Resources