#c# #multithreading #rss
#c# #многопоточность #RSS-канал
Вопрос:
Я хочу создать RSS-ридер, который позволяет получать несколько новостных лент одновременно, без «зависания» моего приложения при получении ленты. Для этого я хочу, чтобы часть кода выполнялась в отдельном потоке. Я пробовал несколько разных способов, чтобы заставить его работать в отдельном потоке, но я продолжаю получать исключения. Мой код выглядит следующим образом 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);
}
}
}
}
}
У кого-нибудь есть несколько примеров того, как справиться с этой проблемой? Примеры кода с моим кодом очень ценятся 🙂
Заранее спасибо.
Ответ №1:
Вы можете проверить класс BackgroundWorker. И вот пример:
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);
}
}
Ответ №2:
Если вы используете .NET 3.5 или более позднюю версию, вы можете использовать SyndicationFeed
тип, чтобы упростить синтаксический анализ RSS-канала.
Я адаптирую пример кода Дарина Димитрова здесь:
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);
}
}
Ответ №3:
Если вы используете .net 4.0, вы можете использовать систему задач для еще более простого подхода и, возможно, повышения производительности.
foreach (var item in rssDoc.XPathSelectElements("//item"))
{
Task fetch = new Task(() =>
{
// Go to server and get data....
// Add Data to UI...
});
fetch.Start();
}
Основным преимуществом здесь является то, что система задач будет решать, как и когда выполнять каждую операцию выборки. Теоретически каждая операция будет выполняться в своем собственном потоке, поэтому одновременно будет активна одна или несколько операций, а не только одна, которую вы бы видели в обычном цикле. Система достаточно хороша, чтобы выполнить некоторую балансировку нагрузки и для вас.