RSS-Leser
Programmet vårt skal abonnere på et antall RSS-filer. Vi lager en klasse "feedlist" for å administrere en slik liste med adresser til RSS-filer.
Hvert feed er beskrevet med en instans av klassen "feed". Den samme klassen brukes også til å ta vare på et Item (en nyhetsrefreanse).
feed
class feed : Object { protected String m_title; protected String m_description; protected Uri m_link; protected XmlDocument m_xmldoc; // constructor based on strings public feed(string t, string u, string d) { title = t; link = new Uri(u); description = d; } // constructor based on feed-node from XML public feed(XmlNode nod) { this.title = String.Empty; this.link = null; this.description = String.Empty; if (nod.HasChildNodes) foreach (XmlNode p in nod.ChildNodes) if (p.GetType() == typeof(XmlElement)) { if (p.LocalName.CompareTo("title") == 0) this.title = p.InnerText; if (p.LocalName.CompareTo("link") == 0) this.link = new Uri(p.InnerText); if (p.LocalName.CompareTo("description") == 0) this.description = p.InnerText; } } public string title { get { return m_title; } set { m_title = value; } } public Uri link { get { return m_link; } set { m_link = value; } } public string description { get { return m_description; } set { m_description = value; } } public XmlDocument xmldoc{ set { m_xmldoc = value; } get { // done already ? if (m_xmldoc != null) return m_xmldoc; // get it try { m_xmldoc = new XmlDocument(); m_xmldoc.Load(link.ToString()); return m_xmldoc; } catch (Exception ex) { return null; } } } // will need this as feeds appear in listboxes public override string ToString(){return title;} // prepare a feed-node as string public String GetPacked() { return String.Format(@" <title>{0}</title> <link>{1}</link> <description>{2}</description>", title, link.ToString(), description); } }
feedlist
class feedlist:Object { // keep up a number of feeds, which sleeps on a file private ArrayList FeedList; private string filename; public feedlist(String filename) { FeedList = new ArrayList(); this.filename = filename; LoadFeeds(); // something to get started with if we have not loaded anything: if (FeedList.Count == 0) FeedList.Add(new feed( "Wired News", "http://www.wired.com/news_drop/netcenter/netcenter.rdf", "Tech review")); } public ArrayList getFeedList(){ return FeedList;} public void LoadFeeds() { // load as XML XmlDocument doc = new XmlDocument(); try { doc.Load(filename); XmlNodeList list = doc.GetElementsByTagName("feed"); foreach(XmlNode n in list) FeedList.Add(new feed(n)); } catch (Exception ex) { MessageBox.Show( "Kan ikke laste opp kildefila: "+ex.Message, "Feilmelding", MessageBoxButtons.OK); return; } } public void SaveFeeds() { // save as text in XML-format FileStream s = null; StreamWriter w = null; try { s = new FileStream(filename, FileMode.Truncate); s.Position = 0; w = new StreamWriter(s); w.WriteLine("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); w.WriteLine("<feeds>"); for (int i = 0; i < FeedList.Count; i++) w.WriteLine("<feed>"+ ((feed)FeedList[i]).GetPacked()+ "</feed>"); w.WriteLine("</feeds>"); w.Flush(); } catch (Exception e) { MessageBox.Show( "Kan ikke spare kildefila: "+e.Message, "feilmelding", MessageBoxButtons.OK); return; } finally { if (w != null) w.Close(); } } }
FeedForm
Når vi skal endre et feed eller lage et nytt feed, gjør vi dette via en dialogboks: "FeedForm".
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; namespace RSS { public partial class FeedForm : Form { public Uri link; public String title; public FeedForm(String t, String l) { InitializeComponent(); this.textBoxTitle.Text = t; this.textBoxLink.Text = l; } private void buttonOK_Click(object sender, EventArgs e) { // is data ok try { link = new Uri(this.textBoxLink.Text); if ((this.textBoxTitle.Text==null)|| (this.textBoxTitle.Text.Length == 0)) title = this.textBoxLink.Text; else title = this.textBoxTitle.Text; this.DialogResult=DialogResult.OK; this.Hide(); } catch(Exception ex){ DialogResult result; result = MessageBox.Show(this, "Kildens adresse (URL) ser ikke bra ut, korrigere ?", "D�rlig lenke", MessageBoxButtons.YesNo); if (result == DialogResult.Yes) return; this.DialogResult = DialogResult.Cancel; this.Hide(); } } } }
Selve logikken er plassert på "Form" klassen:
Form
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Xml; using System.IO; namespace RSS { public partial class Form1 : Form { // will be based on a list of feeds feedlist theFeeds; public Form1() { InitializeComponent(); // establish list of feeds and fill left listbox, feedlist theFeeds = new feedlist(Path.Combine(Application.StartupPath, "..\\..\\feeds.xml")); if (theFeeds == null) return; for(int i=0;i<theFeeds.getFeedList().Count;i++) listBoxFeeds.Items.Add(theFeeds.getFeedList()[i]); // set up a welcome message in webbrowser webBrowser1.DocumentText = Properties.Resources.startpage; } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { // store list of feeds theFeeds.SaveFeeds(); } private void FillUpItemlist(feed f) { // fill up listBoxItems with items from a selected feed XmlDocument doc = f.xmldoc; if (doc == null) { DialogResult result; result = MessageBox.Show(this, "Denne kilden er ikke tilgjengelig", "Finner ikke kilden", MessageBoxButtons.OK); return; } // extract the items and fill up: listBoxItems XmlNodeList list = doc.GetElementsByTagName("item"); listBoxItems.Items.Clear(); for (int nix = 0; nix < list.Count; nix++) { String strTitle = null; String strLink = null; String strDesc = null; XmlNode p = list.Item(nix); if (p.HasChildNodes) { foreach (XmlNode c in p.ChildNodes) { if (c.GetType() == typeof(XmlElement)) { if (c.LocalName.CompareTo("title") == 0) strTitle = c.InnerText; if (c.LocalName.CompareTo("link") == 0) strLink = c.InnerText; if (c.LocalName.CompareTo("description") == 0) strDesc = c.InnerText; } } } listBoxItems.Items.Add(new feed(strTitle, strLink, strDesc)); } } // get all items from this feed private void listBoxFeeds_MouseClick(object sender, MouseEventArgs e) { // we have clicked on a listitem, which one ? int ix = listBoxFeeds.IndexFromPoint(e.X, e.Y); if (ix != -1) { // get all items in the actual feed feed f = (feed)listBoxFeeds.Items[ix]; FillUpItemlist(f); } String tmp = listBoxFeeds.SelectedItem.ToString(); webBrowser1.DocumentText = "<html><body><h2>" + tmp + "</h2></body></html>"; } // produce description of selected item in webbrowser private void listBoxItems_MouseClick(object sender, MouseEventArgs e) { // we have clicked on a listitem, which one ? int ix = listBoxItems.IndexFromPoint(e.X, e.Y); if (ix != -1) { // get information from the actual feeditem feed f = (feed)listBoxItems.Items[ix]; String description = f.description; String title = f.title; Uri link = f.link; // produce HTML String htmlS= String.Format(Properties.Resources.skeleton,title,description,link); webBrowser1.DocumentText = htmlS; } } // we have a right-click in itemlist private void contextMenuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e) { //Which feed is selected ? feed theFeed=(feed)listBoxFeeds.SelectedItem; // what do we want to do with it ? if (e.ClickedItem == this.renameToolStripMenuItem) { // change FeedForm ff = new FeedForm(theFeed.title,theFeed.link.ToString()); ff.ShowDialog(this); if (ff.DialogResult == DialogResult.OK) { theFeeds.getFeedList().Remove(theFeed); theFeeds.getFeedList().Add( new feed(ff.title,ff.link.ToString(),"")); listBoxFeeds.Items.Clear(); for (int i = 0; i < theFeeds.getFeedList().Count; i++) { feed afeed=(feed)theFeeds.getFeedList()[i]; listBoxFeeds.Items.Add(afeed); } } } else if (e.ClickedItem == this.deleteToolStripMenuItem) { // delete it, after a warning DialogResult result; result = MessageBox.Show(this, "Vil du virkelig fjerne denne kilden ?", "Fjern kilde", MessageBoxButtons.YesNo); if (result == DialogResult.Yes) { theFeeds.getFeedList().Remove(theFeed); listBoxFeeds.Items.Clear(); for (int i = 0; i < theFeeds.getFeedList().Count; i++) listBoxFeeds.Items.Add(theFeeds.getFeedList()[i]); listBoxItems.Items.Clear(); } } else if (e.ClickedItem == this.updateToolStripMenuItem) { // update the feed theFeed theFeed.xmldoc = null; FillUpItemlist(theFeed); } } // add a feed private void buttonNew_MouseClick(object sender, MouseEventArgs e) { //Introduce a new feed FeedForm ff = new FeedForm("<title>", "<uri>"); ff.ShowDialog(this); if (ff.DialogResult == DialogResult.OK) { theFeeds.getFeedList().Add( new feed(ff.title, ff.link.ToString(), "")); listBoxFeeds.Items.Clear(); for (int i = 0; i < theFeeds.getFeedList().Count; i++) { feed afeed = (feed)theFeeds.getFeedList()[i]; listBoxFeeds.Items.Add(afeed); } } } // update all feeds private void buttonUpdate_MouseClick(object sender, MouseEventArgs e) { if (theFeeds.getFeedList().Count > 0) { for (int i = 0; i < theFeeds.getFeedList().Count; i++) { feed afeed = (feed)theFeeds.getFeedList()[i]; afeed.xmldoc=null; } // select and show first listBoxFeeds.SelectedIndex=0; FillUpItemlist((feed)listBoxFeeds.SelectedItem); } } // see you later... private void buttonExit_MouseClick(object sender, MouseEventArgs e) { this.Close(); this.Dispose(); } } }
Som du ser dersom du kjører programmet så er det en rekke ting som kan forbedres. Dersom programmet skulle utvikles i retning av et produkt så måtte vi i hvert fall vurdere å:
- forbedre sikkerheten
- bruke threads for oppdatering i bakgrunnen
- forbedre brukergrensesnittet funksjonelt
- gjennomføre en kraftig estetisk "makeover"
- trekke ut mer informasjon fra RSS-filene for å få fram bedre beskrivelse av kildene.
- la programmet ha hukommelse slik at det i tillegg til å huske de kildene vi abonnerer på, også husker et antall tidligere (permanent) items fra disse kildene.