Multiple lines not reading into one list item - c#

For some reason when I read in clipboard data and write it to a file, read that file in and set it to a list after delineating it with ¢ it loads up my listbox just fine on the first load as in when my form first loads up. However I have the following trigger on a button click, it is for some reason splitting up multiple line sections into separate list items, which is not what I want and not what the same code does when the form first loads. It's a little frustrating as it's writing to the text file and everything the same way.
private void button2_Click_1(object sender, EventArgs e)
{
// until next comment this is the same as what I have run at the start of the
// program, it loads up multiple lines into one list item as it should
string checkForDupe = File.ReadAllText(#"C:\temp\testfile.txt");
string checkResponses = File.ReadAllText(#"C:\temp\testfile2.txt");
if (Clipboard.ContainsText() && !checkForDupe.Contains(Clipboard.GetText()))
{
if (!checkResponses.Contains(Clipboard.GetText()))
{
var text = "\n" + Clipboard.GetText() + "¢";
File.AppendAllText(#"C:\temp\testfile.txt", text);
}
}
//The following has no affect on the issue stated in my question I have tried with out it.
string[] responseTags2 = File.ReadAllLines(#"C:\temp\testfile.txt");
List<string> _responseTags2 = new List<string>(responseTags2);
var count = _responseTags2.Count;
// Perform a reverse tracking.
for (var i = count - 1; i > -1; i--)
{
if (_responseTags2[i] == string.Empty) _responseTags2.RemoveAt(i);
}
// Keep only the unique list items.
_responseTags2 = _responseTags2.Distinct().ToList();
listBox1.BeginUpdate();
listBox1.DataSource = _responseTags2;
listBox1.EndUpdate();
}
input example:
"This is multiple lines in
a text file that is for testing
this application"
right output example (what I get when the same code is running at the start of the program before the form is loaded):
"This is multiple lines in
a text file that is for testing
this application" ,
"This is ANOTHER multiple lines in
a text file that is for testing
this application" ,
"This is a single line"
WRONG output (what I get when I run off the button click that eventual updates the UI):
"This is multiple lines in",
"a text file that is for testing",
"this application"

You are getting multiple lines in your listbox because you are not breaking the text by ¢ but just reading them into lines. This is your code:
string[] responseTags2 = File.ReadAllLines(#"C:\temp\testfile.txt");
Do this instead. Read all the text:
var contents = File.ReadAllText(#"C:\temp\testfile.txt");
Now split them using the character ¢:
var lines = s.Split('¢');
Here is the final linq to remove any empties and return distinct items:
var lines = s.Split('¢')
.Where(item => item != string.Empty)
.Distinct()
.ToList();
Then set lines to be the datasource:
listBox1.BeginUpdate();
listBox1.DataSource = lines;
listBox1.EndUpdate();

This code works fine for me, but I think it's basically what you're doing, only slightly cleaned up (and I didn't use the second file since you're not using it in the example).
My suggestion would be to create a single method that does this operation, and then call that method from wherever you need it. This way you will ensure that you're doing the exact same thing in both (all) places.
UPDATE
I updated the method to save the clipboard text as-is, plus adding a ¢ character to the end, when saving to the file. Then, when reading the file the second time, first join all the lines with a space character, then split on the ¢ character, and use that list for your data source.
private const string DefaultSaveFile = #"C:\temp\testfile.txt";
private void CopyUniqueClipboardTextToFile(string filePath = null,
bool updateListbox = true)
{
// Use global default file if nothing was passed
if (filePath == null) filePath = DefaultSaveFile;
// Ensure our files exist
if (!File.Exists(filePath)) File.CreateText(filePath).Close();
string fileContents = File.ReadAllText(filePath);
string clipboardText = Clipboard.GetText();
// Update the file with any new clipboard text
if (Clipboard.ContainsText() && !fileContents.Contains(clipboardText))
{
// Save the lines to our file, with a '¢' character at the end
File.AppendAllText(filePath, $"{Environment.NewLine}{clipboardText}¢");
}
// Re-read the new file into a single string
string entireFileAsOneLine = string.Join(" ",
File.ReadAllLines(filePath).Distinct().ToList());
// Now split that string on the '¢' character
string[] listItems = entireFileAsOneLine.Split('¢');
// Update listbox if necessary
if (updateListbox)
{
listBox1.BeginUpdate();
listBox1.DataSource = listItems;
listBox1.EndUpdate();
}
}
private void button2_Click(object sender, EventArgs e)
{
CopyUniqueClipboardTextToFile();
}

What I ended up doing is the following;
string responseTags2 = checkForDupe.Replace('\n', '╜');
I replaced new lines with a rarely used character, then split by ¢ to fill the list.
To replace the special character so that it would be formatted correctly again I just replaced it when setting the clipboard text with the \n again.

Related

How to display a specific line at the top of a RichTextBox

I'm pulling the content from a text file into a RichTextBox. I've got the RichTextBox set up to where it only shows 6 lines at a time. I've got a search method that finds the text I need within the RichTextBox, but what I am needing it to do is display 6 specific lines. Each "item" in my text file consists of 6 lines. No matter which of the six lines the search method finds the text on, I need the RichTextBox to only display the 6 lines of each "item" with the currently selected "found" text remaining highlighted.
I've gotten it working reasonably well thanks to a few code examples I've pull from this site. But every now and then, it doesn't work entirely well, and am looking for some advice from a fresh set of eyes looking at my code and perhaps even be told an easier/more efficient way to go about it. But here is my code so far. Thanks in advance!
try
{
string s = txtFindPlaylistEntry.Text;
rtxEditPlaylistEntry.Focus();
findPosEntry = rtxEditPlaylistEntry.Find(s, findPosEntry, RichTextBoxFinds.None);
// Jump to the line we need.
int count = rtxEditPlaylistEntry.GetLineFromCharIndex(findPosEntry);
count = (count - (count % 6)) + 1; // Must be divisible by 6 then plus 1
rtxEditPlaylistEntry.SelectionStart = rtxEditPlaylistEntry.Find(rtxEditPlaylistEntry.Lines[count]);
rtxEditPlaylistEntry.ScrollToCaret();
rtxEditPlaylistEntry.Select(findPosEntry, s.Length);
findPosEntry += txtFindPlaylistEntry.Text.Length;
}
catch
{
MessageBox.Show("No occurences found");
findPosEntry = 0;
}
As of right now, I'm attempting to use a line count with modulus plus 1 to get the line I need. Like I said, it works, just not 100% of the time and I can't figure out why.
EDIT to try to accommodate Minimal, Complete, Verifiable.
I've already posted my "find" function. Here is other related code that might be useful. First, here is my code for creating the various controls I am using.
rtxEditPlaylistEntry = new RichTextBox();
rtxEditPlaylistEntry.Location = new System.Drawing.Point(15, 90);
rtxEditPlaylistEntry.Size = new System.Drawing.Size(375, 85);
rtxEditPlaylistEntry.Multiline = true;
rtxEditPlaylistEntry.ScrollBars = RichTextBoxScrollBars.None;
Here is my button function to pull text from a file and place it into the RichTextBox.
private void btnBrowseForPlaylistToEditEntry_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "LPL Files|*.lpl";
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
savedFileNameEntry = openFileDialog.SafeFileName;
txtPathToPlaylistToEditEntry.Text = openFileDialog.FileName;
}
// After finding the file, load it into the richtextbox control
using (StreamReader sr = File.OpenText(openFileDialog.FileName))
{
// Initially show the first 6 lines (IE first entry). This should be accomplished by
// the richtextbox control settings
rtxEditPlaylistEntry.Text = sr.ReadToEnd();
}
previousNextCount = 0;
}
I hope this is sufficient. If not please let me know!

While loop isn't detecting first line of text file

I have a program that loads text files to populate two separate list boxes in the form. It's supposed to read every line, and add each line to a single listbox. The first line of the text file is being ignored for some reason, and I'm not sure why.
This is what each line of the text file is:
cd Armor 1 True+
bg Tool 2 False+
o Weapon 3 False-
xz Consumable 1 True-
I believe my while loop is the issue, but I'm not sure what I'm doing wrong with it. I need the program to loop through more than one line. When I ran the code without using a loop, the first line of the text file was added to the appropriate list box with no issues.
The code below is attached to the load button within my form.
private void loadToolStripMenuItem_Click(object sender, EventArgs e)
{
OpenFileDialog openTextFile = new OpenFileDialog();
openTextFile.Filter = "Text Files (*.txt) | *.txt";
string listItemString;
string[] listItem;
if (openTextFile.ShowDialog() == DialogResult.OK)
{
using (StreamReader openStream = new StreamReader(openTextFile.OpenFile()))
{
listItemString = openStream.ReadLine();
listItem = listItemString.Split(' ');
while ((listItemString = openStream.ReadLine()) != null)
{
if (listItemString.EndsWith("+"))
{
listItemString = listItemString.Replace("+", "");
cart.Items.Add(listItemString);
}
else if (listItemString.EndsWith("-"))
{
listItemString = listItemString.Replace("-", "");
delivery.Items.Add(listItemString);
}
}
}
}
}
You are reading first line before while loop in the line of code listItemString = openStream.ReadLine();. Then you are overridden this value in the first loop iteration when calls while ((listItemString = openStream.ReadLine()) != null) first time.
Just delete 2 lines of code befoer yout loop:
listItemString = openStream.ReadLine();
listItem = listItemString.Split(' ');

How do I replace a part of a line in a text file with user input?

Here's the code.
private void SaveButton_Click(object sender, EventArgs e)
{
string textBoxText = TextBox.Text;
var lines = File.ReadAllLines(#"F:\Bioshock2SP.ini");
foreach(string line in lines)
{
if (line.Contains("VoVolume="))
{
//This is where I get confused.
string settingLine = line;
string replaceline = (line.Replace(line, textBoxText));
File.WriteAllText(#"F:\Bioshock2SP.ini", settingLine);
}
break;
}
MessageBox.Show("Setting saved!");
}
The idea is to replace part of a setting in a Settings.ini file for a game I play, using the user input of a textbox in my form. The user types in a number for example, "1.56" and then hit the Save button to replace the existing line with their input. In this case that setting is the volume.
The application runs completely fine, but after hitting save and going into the settings file my input isn't saved.
There should be a change in the way you save the file.
Save each line of the file as you get it, editing if required.
void SaveButton_Click(object sender, EventArgs e)
{
var textBoxText = TextBox.Text;
var lines = File.ReadAllLines(#"F:\Bioshock2SP.ini");
using (var file = new StreamWriter(#"F:\Bioshock2SP.ini"))
foreach(string line in lines)
{
if (line.Contains("VoVolume="))
file.WriteLine(line.Substring(0, 9) + textBoxText); // Writes something like 'VoVolume=1.56'
else file.WriteLine(line); // No editing required
}
MessageBox.Show("Setting saved!");
}
I think there are a couple of separate issues with your code:
Replace Function
string replaceline = (line.Replace(line, textBoxText));
Replace accepts a string to look for and a string to replace it with. Your first argument is 'line', so it would replace the whole line with the value in textBoxText. I assume you only want to replace a portion of the line with that value. In that case, you need to use something like line.Replace(searchString, textBoxText) where you have previously defined searchString as the text you want to replace. If you don't know what that value is, but there is a pattern, you might want to look into using regular expressions which will let you define a pattern to search and replace.
WriteAllText Function
File.WriteAllText(#"F:\Bioshock2SP.ini", settingLine);
This line will replace the entire contents of BioShock2SP.ini with the value in settingLine. There are two problems here.
One is that settingLine was the saved value before you did the replacement - so it has not included the results of your replace operation. You should use replaceline (assuming it has been correctly modified).
Even if you do that, though, the other is that File.WriteAllText will replace the whole file with the value in settingLine - which is probably not what you want. You'd be better off modifying the line in the array and using File.WriteAllLines to re-output the whole array - assuming the file has multiple lines in it.
The hints above may help you resolve this - to properly answer the question though, I'd need to see a sample of what the file looks like, and the patterns you are trying to replace.

Adding text to a file is displayed in one long line

I am having an issue where when I write text to a second file, it display fine in wordpad where it includes the linebreaks, but in notepad all the text for copyText and richTextBox1.Text appear in one really long line.
How can I fix this? If somebody can include a code snippet with my code then it will be much appreciated as I can see what you have done and changed and I can keep it for reference for futr use.
My code is below where I take text from a text file (Testfile.txt) and insert it into richTextBox1, then when I click on button, text is copied to richText Box2 and is written in second file (_Parsed.txt).
I did a message box on text line and it displays text all without line break. I'm not sure if that is issue but I do need help as deadline is tomorrow and this is only thing I need to sort out and I'm done.
string Chosen_File = "C:\\_Testfile.txt";
string Second_File = "C:\\_Parsed.txt";
string wholeText = "";
private void mnuOpen_Click(object sender, EventArgs e) {
//Add data from text file to rich text box
richTextBox1.LoadFile(Chosen_File, RichTextBoxStreamType.PlainText);
//Read lines of text in text file
string textLine = "";
StreamReader txtReader;
txtReader = new StreamReader(Chosen_File);
do {
textLine = textLine + txtReader.ReadLine() + " ";
}
//Read line until there is no more characters
while (txtReader.Peek() != -1);
richTextBox1.Text = textLine;
txtReader.Close();
}
}
private void Write(string file, string text) {
//Check to see if _Parsed File exists
//Write to _Parsed text file
using(StreamWriter objWriter = new StreamWriter(file)) {
objWriter.Write(text);
objWriter.Close();
}
}
private void newSummaryMethod(string copyText) {
//Write into richTextBox2 all relevant text
copyText = richTextBox1.Text;
wholeText = richTextBox1.Text + copyText
Write(Second_File, wholeText);
}
private void btn1_Click(object sender, EventArgs e) {
newSummaryMethod(copyText);
}
The problem is probably with the line breaks in your text file(s).
TextBoxes expect \r\n sequence as an indication of the end-of-line, and your text files may contain only the \n.
Try to make this change to your code:
do {
textLine = textLine + txtReader.ReadLine() + "\r\n";
}
//Read line until there is no more characters
while (txtReader.Peek() != -1);
The problem is that you are never adding a new line to the file in your code. you are using objWriter.Write(text); which does not generate a new line.
you can use objWriter.WriteLine(text); instead and it will automatically add new line character at the end.
I think the difference in viewing the file is because the "word wrap" option is turned on in "wordpad" and it causes to break a long line into multiple line.

Multi-line textbox shows mult-line string as One-Line

I am making a program where you enter an item's name and it's description. Then you add it to a listbox and after you are done you can save all the items to a 'txt' file. (Using StreamWriter). This program also has an edit button that allows you to edit the description in the listbox by removing it first from the listbox and then showing it back in the textbox (, so you can edit it)
If the description is multi-line, it will successfuly show it multi-line when I select it in the listbox and click the edit button that will show it back in the textbox. BUT if I save all the items in the listbox to a file first. And then open up the file again so it load the items back into the listbox. And then clicking the edit button...
The multi-line description will show as a one-line description in the textbox.
I am not sure why - but I've also made a label that will show the exact string that the textbox is suppose to show and the label is showing it multi-lined while textbox isn't!
The string is definitely multi-line but the multi-line textbox is showing it one-line after loading the items back into the listbox using StreamReader.
Example of the multi-line string: (named "theString1")
This is line 1
This is line 2
Using the following code: TextBox1.Text = theString1; this appears in the text box:
This is line1This is line2
But if I use the same code with a label. It will show it correctly.
If someone can explain to me why this is happening I will be more than happy. I just need an explanation.
Thanks in advance.
---[More info]---
Just so you know. I came up with this code myself so it is probably set-up all wrong.
I will be happy if you tell me a better way to do this.
I am using a list to store the description text + the item name. I seperated these two using '`' .And splited the string (see code).
This is the code that happens when you click the edit button. It removes the item from
the listbox and shows it in the textbox so you can edit it and add to listbox again:
int index = listBox.SelectedIndex;
itemName.Text = listBox.SelectedItem.ToString();
var descVar = descList.ElementAt(index).Split('`');
string theString1 = descVar[1];
TextBox1.Text = theString1;
This is how it saves it to a file:
FileDialog save = new SaveFileDialog();
save.Title = "Save information...";
save.DefaultExt = "Text File|*.txt";
save.Filter = "Text File|*.txt";
if (save.ShowDialog() == DialogResult.OK)
{
StreamWriter sw = new StreamWriter(save.FileName);
foreach (string s in listBox.Items) //This writes the names of item names.
{
sw.WriteLine(s);
}
sw.WriteLine("`1`"); //I use this to seperate the item names from description.
foreach (string s in descList) //This writes the descriptions that are stored in a list named "descList".
{
sw.WriteLine(s);
sw.WriteLine("``"); //I use this to seperate descriptions from each other because they are multi-line.
}
sw.WriteLine("`2`"); //Just something so I know where it ends. :D
sw.Close();
}
else
{
}
And this is how it loads: (This can definitely be better!)
FileDialog load = new OpenFileDialog();
load.Title = "Load information...";
load.DefaultExt = "Text File|*.txt";
load.Filter = "Text File|*.txt";
if (load.ShowDialog() == DialogResult.OK)
{
List<string> loadDesc = new List<string>(); //Don't ask you will see why
descList.Clear();
while (listBox.Items.Count > 0) //This removes all items in the listbox to load new ones.
{
int index = 0;
listBox.Items.RemoveAt(index);
descList.Clear();
itemName.Text = "";
}
StreamReader rw = new StreamReader(load.FileName);
for (; true; )
{
string read = rw.ReadLine();
if (read == "`1`") //When it reaches the separator I made it stops reading.
{
break;
}
else
{
listBox.Items.Add(read);
}
}
for (; true; )
{
string read = rw.ReadLine();
if (read == "`2`")
{
break;
}
else
{
loadDesc.Clear();
loadDesc.Add(read);
for (; true; ) //Please tell me if this can be done differently.
{
string read2 = rw.ReadLine();
if (read2 != "``") //This will keep reading the whole description until it reaches the separator.
{
loadDesc.Add(read2); //Adds each line into the list I created.
}
else
{
break;
}
}
string oneBigString = string.Join("\n", loadDesc); //This basically converts all strings in a list into one string.
descList.Add(oneBigString); //And this finally add the string to the main list from where it then loads.
}
}
}
else
{
}
I believe that is it.
If there is anything else you need - tell me.
string oneBigString = string.Join("\n", loadDesc); is where the issue is.
Use Environment.NewLine instead of \n
I'm also just going to go over a couple of things that could be improved with your code (there are a lot, but I just want to cover a couple).
while (listBox.Items.Count > 0) //This removes all items in the listbox to load new ones.
You don't need to iterate over every element in the listbox to remove it. You can just do listBox.clear()
Also, using break to get out of loops is generally bad practice. This should be written as...
for (; true; )
{
string read = rw.ReadLine();
if (read == "`1`") //When it reaches the separator I made it stops reading.
{
break;
}
else
{
listBox.Items.Add(read);
}
}
this
string read = rw.ReadLine()
while(read != "`1`")
{
listBox.Items.Add(read);
read = rw.ReadLine()
}
but theres more, what if 1 is never found in the file? It would crash your program, so you also need to check if there is more data to be read...
string read = rw.ReadLine()
while(read != "`1`" && !sw.EndOfStream) // Make sure you're not at the end of the file
{
listBox.Items.Add(read);
read = rw.ReadLine()
}

Categories