RSS reader multiple threads C# - c#

I want to make a RSS reader which makes it possible to get multiple news feeds at the same time, without my application "freezing" while getting the feed. To do this, I want some of the code to run in a seperate thread. I have tried some different things, to make it run in a seperate thread, but I keep getting exceptions. My code looks like this atm:
namespace NewsReader
{
public partial class Form1 : Form
{
XmlTextReader rssReader;
XmlDocument rssDoc;
XmlNode nodeRss;
XmlNode nodeChannel;
XmlNode nodeItem;
ListViewItem rowNews;
public Form1()
{
InitializeComponent();
}
private void btnRead_Click(object sender, EventArgs e)
{
//Creates a XmlTextReader which reads from the url entered in input field
rssReader = new XmlTextReader(txtUrl.Text);
//Creates an xml doc to save the content of the entered path
rssDoc = new XmlDocument();
//Loads the xml content from the reader into a XmlDocument
rssDoc.Load(rssReader);
//Make a loop to search for the <rss> tag
for (int i = 0; i < rssDoc.ChildNodes.Count; i++)
{
//If the childenode is the rss tag
if (rssDoc.ChildNodes[i].Name == "rss")
{
//the <rss> tag is found, and we know where it is
nodeRss = rssDoc.ChildNodes[i];
}
}
//Make a loop to search for the <channel> tag
for (int i = 0; i < nodeRss.ChildNodes.Count; i++)
{
//If the childnode is the channel tag
if (nodeRss.ChildNodes[i].Name == "channel")
{
//The channel tag is found and we know where it is
nodeChannel = nodeRss.ChildNodes[i];
}
}
//Make a loop to search for the <item> tag
for (int i = 0; i < nodeChannel.ChildNodes.Count; i++)
{
//If the childnode is the item tag
if (nodeChannel.ChildNodes[i].Name == "item")
{
//the item tag is found, and we know where it is
nodeItem = nodeChannel.ChildNodes[i];
//Creates a new row in the LstView which contains information from inside the nodes
rowNews = new ListViewItem();
rowNews.Text = nodeItem["title"].InnerText;
rowNews.SubItems.Add(nodeItem["link"].InnerText);
lstView.Items.Add(rowNews);
}
}
}
}
}
Does anyone have some examples of how to handle this problem? Code examples with my code is very appreciated :)
Thanks in advance.

You may checkout the BackgroundWorker class. And here's an example:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using System.Xml.Linq;
using System.Xml.XPath;
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync(txtUrl.Text);
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
var rssDoc = XDocument.Load((string)e.Argument);
var items = new List<ListViewItem>();
foreach (var item in rssDoc.XPathSelectElements("//item"))
{
var listItem = new ListViewItem();
listItem.Text = item.Element("title").Value;
listItem.SubItems.Add(item.Element("link").Value);
items.Add(listItem);
}
e.Result = items.ToArray();
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
lstView.Items.AddRange((ListViewItem[])e.Result);
}
}

If you're using .NET 3.5 or later you can use the SyndicationFeed type to make parsing the RSS feed easier.
I'm adapting Darin Dimitrov's code example here:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using System.ServiceModel.Syndication;
using System.Xml.Linq;
using System.Xml.XPath;
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync(txtUrl.Text);
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
var reader = new XmlTextReader((string)e.Argument);
var feed = SyndicationFeed.Load(reader);
var items = new List<ListViewItem>();
foreach (var item in feed.Items)
{
var listItem = new ListViewItem();
listItem.Text = item.Title;
foreach (var link in item.Links)
{
listItem.SubItems.Add(link.Uri.AbsoluteUri);
}
items.Add(listItem);
}
e.Result = items.ToArray();
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
lstView.Items.AddRange((ListViewItem[])e.Result);
}
}

If you are using .net 4.0 you can use the Task system for an even easier approach, and possibly better performance.
foreach (var item in rssDoc.XPathSelectElements("//item"))
{
Task fetch = new Task(() =>
{
// Go to server and get data....
// Add Data to UI...
});
fetch.Start();
}
The main benefit here is the Task system will decide how and when to run each fetch operation. In theory each operation will run in its own thread, so one or more at a time will be active instead of just one that you would see in a normal loop. The system is nice enough to do some load balancing for you too.

Related

The process cannot access the file because it is being used by another process Streamwriter

I am getting an error that my textfile that is used to create and save my dictionary is being used by another process, I have used Process explorer to no result on what could be using my file. Below is my code and the code throwing this error.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
namespace meade_9_10
{
public partial class Form1 : Form
{
private Dictionary<string, string> names = new Dictionary<string, string>()
{
};
public Form1()
{
//Make sure Form1 is loaded and ran on program open
InitializeComponent();
this.Load += Form1_Load;
}
private void Form1_Load(object sender, EventArgs e)
{
//Grab myfile.txt and convert to array
StreamReader sr = new StreamReader("myfile.txt");
string line;
while ((line = sr.ReadLine()) != null)
{
string[] arr = line.Split(',');
int i = 0;
//Add array objects to names dictionary
while (i < arr.Length)
{
names[arr[i]] = arr[i + 1];
i += 2;
}
}
}
private void btnAdd_Click(object sender, EventArgs e)
{
//declare variables
string nameAdd;
string emailAdd;
//Put user input into variable
nameAdd = txtNameAdd.Text;
emailAdd = txtEmailAdd.Text;
//Declare new dictionary key pair as user input
names[emailAdd] = nameAdd;
//clear the textbox controls
txtNameAdd.Text = "";
txtEmailAdd.Text = "";
}
private void btnDelete_Click(object sender, EventArgs e)
{
string emailDel;
emailDel = txtEmailDel.Text;
//Remove key pair that is inputted by user
names.Remove(emailDel);
}
private void btnChange_Click(object sender, EventArgs e)
{
//Declare variables
string emailDel;
string nameAdd;
string emailAdd;
//Assign values to variables
emailDel = txtEmailChange.Text;
nameAdd = txtNameNew.Text;
emailAdd = txtEmailNew.Text;
//Delete the user inputted email to change
names.Remove(emailDel);
//Add the new key pair values to dictionary
names.Add(emailAdd, nameAdd);
}
private void btnLookUp_Click(object sender, EventArgs e)
{
//Declare variable
string email = txtEmail.Text;
//If statement to check if dictionary contains key value
if (names.ContainsKey(email))
{
outputName.Text = names[email];
outputEmail.Text = email;
}
}
private void btnExit_Click(object sender, EventArgs e)
{
//writes the names dictioanry to array inside text file
File.WriteAllLines("myfile.txt",
names.Select(x => x.Key + "," + x.Value ).ToArray());
//Closes the program
this.Close();
}
}
}
The part of my code giving me the error
System.IO.IOException: 'The process cannot access the file 'C:\Users\Adrian\Desktop\ALL SCHOOL FILES\Fall 2021\C#\meade_9_10\bin\Debug\myfile.txt' because it is being used by another process.'
is
names.Select(x => x.Key + "," + x.Value ).ToArray());
I just cannot figure out what process is using my text file that is breaking this program, it was working earlier and I haven't made any changes except for removing redundant white space between functions.
Try using the
StreamReader.Close() method after your innermost while loop:
Closes the StreamReader object and the underlying stream, and releases any system resources associated with the reader.
Alternatively, you can use the using statement:
Provides a convenient syntax that ensures the correct use of IDisposable objects.

Editing text file when updating row

I am able to read my text file however when I go and click my edit button it moves all the current rows in the text file to the top row and doesn't update anything. Also how would I go about adding a row to the text file without moving the rows?
private void btnEdit_Click(object sender, EventArgs e)
{
BugTrackers cs = Bugs[index];
// DisplayBugs();
// Update datafile
UpdateBugsInfo();
}
private void UpdateBugsInfo()
{
if (lstBugs.SelectedIndex > -1)
{
System.IO.StreamWriter sw = new System.IO.StreamWriter("smBugs.txt", false);
for (int i = 0; i <= Bugs.Count - 1; i++)
{
sw.Write(Bugs[i].BugsName);
sw.Write(",");
sw.Write(Bugs[i].BugsDesc);
}
sw.Close();
}
}
The StreamWriter object you are creating is having wrong parameter value for append. You need to set that as true OR just remove that parameter since it’s default value is true.
System.IO.StreamWriter sw = new System.IO.StreamWriter("smBugs.txt", true);
OR
System.IO.StreamWriter sw = new System.IO.StreamWriter("smBugs.txt");
Here is the link from Microsoft.
https://learn.microsoft.com/en-us/dotnet/api/system.io.streamwriter.-ctor?view=netframework-4.7.2#System_IO_StreamWriter__ctor_System_String_System_Boolean_
You are also not using the using statement, which ensures the StreamWriter object is removed from memory when no longer needed. Please go through this article to understand it better.
https://www.dotnetperls.com/streamwriter
Hope this helps!
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
namespace BugTracker
{
struct BugTrackers
{
public string BugsName;
public string BugsDesc;
}
public partial class YoungKidsBugTracker : Form
{
// Field to hold a list of BugTrackers objects
private List<BugTrackers> Bugs = new List<BugTrackers>();
private int index; // index fo selected bugs in combobox
public YoungKidsBugTracker()
{
InitializeComponent();
}
private void ReadFile()
{
try
{
//Declare a varialble to hold Bugs Name
StreamReader inputFile; // To Read the file
string line; // To hold a line from the file
// Create an instance of the Bug Accounts
BugTrackers entry = new BugTrackers();
// Create a delimeter array
char[] delim = { ',' };
// Open the file and get a StreamReader Object
inputFile = File.OpenText("smBugs.txt");
// Read the file's contents
while (!inputFile.EndOfStream)
{
// Read a line from the file
line = inputFile.ReadLine();
// Tokenize the line
string[] tokens = line.Split(delim);
// Stores the tokens in the entry object
entry.BugsName = tokens[0];
entry.BugsDesc = tokens[1];
// Add the entry object to the combobox
Bugs.Add(entry);
}
// Close the File
inputFile.Close();
}
catch (Exception ex)
{
// Display an error message
MessageBox.Show(ex.Message);
}
}
private void lstBugs_SelectedIndexChanged(object sender, EventArgs e)
{
// Get the index of the sselected item
index = lstBugs.SelectedIndex;
// Display Bug Information
DisplayBugs();
}
private void DisplayBugs()
{
//Show Data
txtBugsName.Text = Bugs[index].BugsName;
rtxtBugDesc.Text = Bugs[index].BugsDesc.ToString();
}
private void YoungKidsBugTracker_Load(object sender, EventArgs e)
{
// Read the Bugs.txt file
ReadFile();
// Display Bug Information
BugNameDisplay();
}
private void btnEdit_Click(object sender, EventArgs e)
{
BugTrackers cs = Bugs[index];
// DisplayBugs();
// Update datafile
UpdateBugsInfo();
}
private void UpdateBugsInfo()
{
if (lstBugs.SelectedIndex > -1)
{
System.IO.StreamWriter sw = new System.IO.StreamWriter("smBugs.txt");
for (int i = 0; i <= Bugs.Count - 1; i++)
{
sw.Write(Bugs[i].BugsName);
sw.Write(",");
sw.WriteLine(Bugs[i].BugsDesc);
// sw.Write(Environment.NewLine);
}
sw.Close();
}
}
private void BugNameDisplay()
{
// Display the list of Bug Names in the List Control
foreach (BugTrackers entry in Bugs)
{
lstBugs.Items.Add(entry.BugsName );
}
}
private void btnAdd_Click(object sender, EventArgs e)
{
}
}
}
This is the code in its entirety. I have a list box with 2 text boxes to hold the bug name and description. I have 3 buttons Add, Edit and Delete. If an item is selected from the listbox it will display the bugname and description. If the entry needs updated changes are made and will change the information needed. If a new bug is added you would use the add button same for the delete button.

Making dynamic check boxes perform and action c#

I'm working on making a program give the ability to allow the user to set a target of an active window.
I have two problems with my code, perhaps someone can let me know if the path i've chosen is wrong or there is a better path.
The Window output is only showing 16 characters of the name of the process.
I have the check box listed but don't know how to dynamically assign them to do the change where it will make the TextBox.Text Change.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
namespace Workspace
{
public partial class Form5 : Form
{
string target = File.ReadAllText("./target.txt");
public Form5()
{
InitializeComponent();
//Shows current target in textbox.
string target = File.ReadAllText("./target.txt");
textBox1.Text = target;
// Sets a starting point.
int total_processes = 0;
// Captures proccesses.
Process[] processlist = Process.GetProcesses();
//looks at all proccess to separate with titles.
foreach (Process process in processlist)
{
//calculates total proccess with titles.
if (!String.IsNullOrEmpty(process.MainWindowTitle))
{
total_processes = total_processes + 1;
}
}
// Sets up string array total by number of processes with name.
string[] stringArray = new string[total_processes];
//Names each proccess array.
int loopnum = 0;
foreach (Process process in processlist)
{
if (!String.IsNullOrEmpty(process.MainWindowTitle))
{
stringArray[loopnum] = process.MainWindowTitle;
loopnum = loopnum + 1;
}
}
// Generates # of Radio buttons per proccess with name.
System.Windows.Forms.RadioButton [] radioButtons = new System.Windows.Forms.RadioButton[total_processes];
for (int i = 0; i < total_processes; ++i)
{
radioButtons[i] = new RadioButton();
radioButtons[i].Text = stringArray[i];
radioButtons[i].Location = new System.Drawing.Point(10, 10 + i * 20);
radioButtons[i].CheckedChanged += new EventHandler(this.radioButtons_CheckChanged);
this.Controls.Add(radioButtons[i]);
}
}
private void radioButtons_CheckChanged(object sender, EventArgs e)
{
// Dynamic Check box if checked changes textBox1.Text to radioButtons[i].Text
}
private void button1_Click(object sender, EventArgs e)
{
System.IO.StreamWriter file = new System.IO.StreamWriter("./target.txt");
file.WriteLine(textBox1.Text);
file.Close();
}
}
}
Use ((System.Windows.Forms.RadioButton)sender).Text to get the text property of your radio button:
private void radioButtons_CheckChanged(object sender, EventArgs e)
{
textBox1.Text= ((System.Windows.Forms.RadioButton)sender).Text;
}
When an event raises, the sender cotains a reference to your control that raised the event, so you can access properties of sender control.

Not able to fire SelectedNodeChanged event for populated TreeView node

I need to dynamically generate several treeview on my code and I want to be able to load nodes on demand. I have below code structures. My problem is SelectedNodeChanged event for populated TreeView node will not fire. Once you run below code sample, if you expand child node to several level and then click the child node, the label will not show text and the populated nodes collapse. Any idea is appreciated!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class TreeViewTest : System.Web.UI.Page
{
private const int Count = 2;
private string[] codeList = { "th", "os" };
protected void Page_Load(object sender, EventArgs e)
{
updateTree();
}
protected void updateTree()
{
treePanel.Controls.Clear();
TreeView[] treeList = new TreeView[Count];
for (int i = 0; i < Count; i++)
{
var tree = new TreeView();
tree.ID = "treelist" + i.ToString();
tree.TreeNodePopulate += TreeBranch_SelectedNodePopulate;
tree.SelectedNodeChanged += TreeBranch_SelectedNodeChanged;
string codeName = codeList[i];
TreeNode codeNode = new TreeNode(codeName, codeName);
codeNode.SelectAction = TreeNodeSelectAction.Select;
codeNode.PopulateOnDemand = true;
tree.Nodes.Add(codeNode);
tree.ExpandDepth = 2;
treePanel.Controls.Add(tree);
treeList[i] = tree;
}
}
protected void TreeBranch_SelectedNodeChanged(object sender, EventArgs e)
{
TreeView treeview = (TreeView)sender;
string text = treeview.SelectedNode.Text;
Label1.Text = text;
}
protected void TreeBranch_SelectedNodePopulate(object sender, TreeNodeEventArgs e)
{
LoadChildNode(e.Node);
}
public void LoadChildNode(TreeNode parentNode)
{
TreeNode childNode = new TreeNode("childNode","childNode");
parentNode.ChildNodes.Add(childNode);
childNode.PopulateOnDemand = true;
}
}
Try the following code.
treePanel.Controls.Clear();
TreeView[] treeList = new TreeView[codebaseCount]; //But I recommend you use List<TreeView> instead of TreeView[];
for (int i = 0; i < codebaseCount; i++)
{
var tree = new TreeView();
tree.ID = "treelist" + i.ToString();
tree.TreeNodePopulate += TreeBranch_SelectedNodePopulate;
tree.SelectedNodeChanged += TreeBranch_SelectedNodeChanged;
TreeNode newNode = new TreeNode(newName,newName);
newNode.SelectAction = TreeNodeSelectAction.None;
newNode.Expand();
tree.Nodes.Add(newNode);
tree.ExpandDepth = 2;
treePanel.Controls.Add(tree);
treeList[i] = tree;
// more code ...
}

How can i load item from a listBox as file and show the file content?

I have this Code in Form1. Im doing a search for xml files. When i find them im using listBox1 selected index changed event and i want to do that when i select item in the lixtBox it will consider it as a file will parse it content and show me the parsed content.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using System.IO;
using System.Collections;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
DirectoryInfo dirinf = new DirectoryInfo(#"C:\");
List<FileSystemInfo> fsi = new List<FileSystemInfo>();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
button1.Enabled = false;
}
private void ParseAndDisplayXml(string filename)
{
XDocument document = XDocument.Load(filename);
var list = document.Root.Elements("Message")
.Select(
e => new
{
Date = e.Attribute("Date").Value.ToString(),
Time = e.Attribute("Time").Value.ToString(),
Text = e.Element("Text").Value.ToString()
}
);
string result="";
foreach (var item in list)
{
result += string.Format("Date--{0},Time--{1},Text--{2}", item.Date, item.Time, item.Text + Environment.NewLine);
}
}
public void Search(string strExtension,
DirectoryInfo di,
List<FileSystemInfo> pResult)
{
try
{
foreach (FileInfo fi in di.GetFiles())
{
if (InvokeRequired)
{
BeginInvoke(new Action(() => label2.Text = fi.Name));
}
if (fi.Name == "MessageLog.xsl")
{
foreach (FileInfo fii in di.GetFiles())
{
if (fii.Extension == strExtension)
pResult.Add(fii);
}
if (InvokeRequired)
{
BeginInvoke(new Action(() => label4.Text = pResult.Count.ToString() + Environment.NewLine));
}
}
}
foreach (DirectoryInfo diChild in di.GetDirectories())
Search(strExtension, diChild, pResult);
}
catch (Exception e)
{
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
Search(".xml", dirinf, fsi);
backgroundWorker1.ReportProgress(100);
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
for (int i = 0; i < fsi.Count; i++)
{
listBox1.Items.Add(fsi[i].Name + Environment.NewLine);
}
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
label2.Text = listBox1.SelectedItem.ToString();
}
}
}
Im starting the search from C:\
Then when the search so over completed im adding the items it found to the listBox1.
For example now in my listBox1 i have 4 files:
danny.xml
adi.xml
sharon.xml
yoval.xml
In the selectedindexchanged i added option so the user can move between the items.
Now what i want to do is when the user select some index for example index [1] in the listBox and only if he clicked enter with the keyboard or clicked with the mouse left click it will call/use the function: ParseAndDisplayXML.
Then it will parse the selected index wich need to be translated to a file so in the backgroundWorker1_RunWorkerCompleted event i madding the files to the listBox as items but only with the names of the files. If i did .FullName instead .Name it was adding the files names with the directories too.
So i need somehow to get the FullName of the files in the completed event i think then when selecting one of the FullName items to parse it and display it in the listBox.
The parse function should take the specific content from the xml files and it worked i checked this function before alone.
The problem is how do i make that the user will select the index by click/key enter and how to parse and display it ?
When you add something to a listbox.
It expects an object, and sets the text to object.ToString()
e.g.
MyListBox.Add(100);
Would box 100 and display "100"
Couldn't find if FileSystemInfo's ToString() method has been overridden but first thing to try would be
private void backgroundWorker1_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
// newline is unnecesary and you should be using foreach
foreach(FileSystemInfo f in fsi)
{
listBox1.Items.Add(f);
}
}
// display full name of file
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
label2.Text = ((FileSystemInfo)listBox1.SelectedItem).Fullname;
}
If FileSystemInfo.ToString() doesn't return Name, there are a few ways to deal with that.
If you don't want to hold on to the FileSystemInfo instances, we can deal with that too.

Categories

Resources