Introduction
I often see illuminated news display on building walls in towns, which scroll news title after title. In the web, could we see the same thing? Hundreds of RSS sites feed thousands of news every day. If we could see the scrolling news titles in the tool bar of IE/Explorer and read their details with just one click, it'd be cool wouldn't it be? So I made this. RSSbar is an RSS aggregator in the tool bar.
Background
I used the code of BandObject
by Pavel Zolnikov to make the tool bar, which was very easy to use. It really liberated me from the complicated COM programming. Thanks so much for the great code!
First setup
After installing the demo project with Setup.msi, RSSbar is available through 'View->Explorer Bars' and 'View->Toolbars' in IE/Explorer menus. Clicking 'RSSbar' menu item, a handle will appear at the right edge of the existing tool bar. You can drag the handle and set the position and length so that each news title can be seen. Then click the button at the left end and select 'Add' in the dropdown menu to register the URLs of RSS feeds. After registering the URLs in the dialog below, top titles of RSS feeds will appear in the dropdown menu. OK? Then just click whichever title you want to see.
Custom collection class
Main logic of the RSSbar is quite simple. After reading the XML file of the RSS feed, it creates LinkLabel
s as many as news titles dynamically, puts them on the panel of RSSbar, and moves them with a timer at constant speed. In order to do that, I've made a custom collection class LinkLabalArray
, which manages the collection of LinkLabel
s and also handles the click event of each LinkLabel
; it means jump to the detail page of each title with Navigate
method of IWebBrowser2
interface of BandObject
. maxlblWidth
property gets the width of the longest title in the collection. I will mention later the reason why this is needed.
public class LinkLabelArray : CollectionBase
{
private readonly UserControl hostControl;
private WebBrowserClass webControl;
private static bool bFirst = true;
public LinkLabelArray(UserControl host)
{
hostControl = host;
}
public void AddNewLinkLabel()
{
LinkLabel aLabel = new LinkLabel();
this.List.Add(aLabel);
((RSSBar)hostControl).panel1.Controls.Add(aLabel);
aLabel.AutoSize = true;
aLabel.LinkVisited = true;
aLabel.Visible = true;
aLabel.Top = 5;
aLabel.Height = 15;
aLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
aLabel.LinkClicked += new LinkLabelLinkClickedEventHandler(ClickHandler);
}
public LinkLabel this [int Index]
{
get
{
return (LinkLabel) this.List[Index];
}
}
public int maxlblWidth
{
get
{
int max = 0;
IEnumerator myEnum = this.GetEnumerator();
while(myEnum.MoveNext())
{
if(((LinkLabel)myEnum.Current).Width > max)
max = ((LinkLabel)myEnum.Current).Width;
}
return max;
}
}
public new void Clear()
{
((RSSBar)hostControl).panel1.Controls.Clear();
this.List.Clear();
}
public void ClickHandler(Object sender, LinkLabelLinkClickedEventArgs e)
{
if(bFirst)
{
webControl = ((RSSBar)hostControl).getExplorer;
bFirst = false;
}
object Null = System.Reflection.Missing.Value;
((LinkLabel)sender).Links[0].Visited = true;
((IWebBrowser2)webControl).Navigate(e.Link.LinkData.ToString(),
ref Null,ref Null,ref Null,ref Null);
}
}
I've also made another collection class MenuItemArray
to append dropdown menu items dynamically upon user's registration of RSS feed URLs.
Read XML of RSS feed
To make the LinkLabel
collection, we have to read the XML file of the RSS feed. It is the job of rssRead
method in RSSbar
class. At first it checks the format of XML and if it is a valid RSS feed, then gets the list of 'item' nodes which includes news titles and links we are interested in. After that, it makes the LinkLabel
collection LinkLabelArray
, one LinkLavel
for each node, sets title and link to each LinkLabel
while setting the position of each label displayed in the panel, just behind the previous one. That's all.
public void rssRead(string Url)
{
this.panel1.Width = defaultPanelWidth;
XmlDocument xmlDoc= new XmlDocument();
try
{
xmlDoc.Load(Url);
}
catch(XmlException)
{
MessageBox.Show("Not RSS feed!!");
return;
}
XmlElement root = xmlDoc.DocumentElement;
if(root.Name != "rss" && root.Name != "rdf:RDF")
{
MessageBox.Show("Not RSS feed!!");
return;
}
XmlNodeList itemList = root.GetElementsByTagName("item");
if(itemList.Count != 0)
{
int itemCount;
if(itemList.Count < maxItems)
{
itemCount = itemList.Count;
}
else
itemCount = maxItems;
int dispLeft = 0;
for (int i=0;i < itemCount; i++)
{
XmlNode item = itemList[i];
lblArray.AddNewLinkLabel();
for (int j=0; j < item.ChildNodes.Count; j++)
{
XmlNode chld = item.ChildNodes[j];
switch (chld.Name)
{
case "title":
{
lblArray[i].Text = chld.InnerText;
break;
}
case "link":
{
lblArray[i].Links.Add(0,lblArray[i].Text.Length,
chld.InnerText);
break;
}
}
}
lblArray[i].Left = dispLeft;
dispLeft += lblArray[i].Width;
}
if(this.panel1.Width > dispLeft - lblArray.maxlblWidth)
this.panel1.Width = dispLeft - lblArray.maxlblWidth;
}
}
Cyclic Formula
There was one critical problem to solve in making the RSSbar. In order to circulate news titles in the tool bar continuously without any break, I just reset the position of the first title to the tail of the last title as soon as the last one entirely appeared at the right edge of the panel, and the second title to the tail of the first one and so forth, like this:
private void timer1_Tick(object sender, System.EventArgs e)
{
for(int i = 0; i < lblArray.Count; i++)
{
lblArray[i].Left -= 1;
if(lblArray[i==0 ? lblArray.Count-1:i-1].Right ==
this.panel1.Width && lblArray[i].Right < 0)
{
lblArray[i].Left = this.panel1.Width;
}
}
}
This functioned pretty well, as long as the total length of news titles is longer enough than the panel length. Otherwise this function fails because I didn't want to duplicate LinkLabel
of the same title just to fill the panel. As a result, intervals of each title turned out to be far from constant, looks quite ugly. After several trials, I hit upon an idea of changing the length of the panel itself according to the total length of titles. And this is the 'Cyclic Formula' I've found:
panel length <= total length of titles - length of the longest title
This formula is used at the end of rssRead
method presented before, to set panel length properly with the help of maxlblWidth
property of LinkLabelArray
class.
Apply XP style
In order to apply XP style (Visual Style) to the tool bar button and dialog, I used
EnableVS
class I found in FAQ messages in the
BandObject
article, which calls
CreateActCtx
and
ActivateActCtx
Win32 functions instead of using '
.dll.manifest' file which failed eventually. Very smart! Thanks to anonymous one!
History
- First version - May 14, 2005.