Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

RSS bar using BandObject

0.00/5 (No votes)
14 May 2005 1  
RSS aggregator in tool bar of IE/Explorer.

Sample Image - RSSbar1.gif

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.

Sample Image - RSSbar2.gif

Custom collection class

Main logic of the RSSbar is quite simple. After reading the XML file of the RSS feed, it creates LinkLabels 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 LinkLabels 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; //RSSbar instance

    }


    public void AddNewLinkLabel()
    {
        LinkLabel aLabel = new LinkLabel();
        this.List.Add(aLabel);
        ((RSSBar)hostControl).panel1.Controls.Add(aLabel);

        //set linklabel properties

        aLabel.AutoSize = true;
        aLabel.LinkVisited = true;
        aLabel.Visible = true;
        aLabel.Top = 5;
        aLabel.Height = 15;
        aLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
        // handler for clicked event of news title label

        aLabel.LinkClicked += new LinkLabelLinkClickedEventHandler(ClickHandler);
    }

    public LinkLabel this [int Index]
    {
        get
        {
            return (LinkLabel) this.List[Index];
        }
    }

    public int maxlblWidth //get the length of the longest news title

    {
        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)
        //get the instance of explorer only once for the first clicked event

        {
            webControl = ((RSSBar)hostControl).getExplorer; 
            bFirst = false;
        }
        object Null = System.Reflection.Missing.Value;
        ((LinkLabel)sender).Links[0].Visited = true;
        // navigate to the url of the clicked linklabel

        ((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; //reset panel length

    XmlDocument xmlDoc= new XmlDocument();

    // check the url if it is Rss feed or not

    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;
    }

    // collect item nodes, each item contains news title and link node

    XmlNodeList itemList = root.GetElementsByTagName("item");

    if(itemList.Count != 0)
    {
        // set number of the news titles to display

        int itemCount;
        if(itemList.Count < maxItems)
        {
            itemCount = itemList.Count;
        }
        else
            itemCount = maxItems;

        int dispLeft = 0;
        // this variable holds total length of news titles at the end of loop


        for (int i=0;i < itemCount; i++)
        {
            XmlNode item = itemList[i]; //each item node

            lblArray.AddNewLinkLabel(); // making new title label


            for (int j=0; j < item.ChildNodes.Count; j++)
            {
                XmlNode chld = item.ChildNodes[j];
                // we are interested only in the title and link node

                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;
                    }
                }                        
            }
            //set display position of each title label in the panel

            lblArray[i].Left = dispLeft;
            //set position just behind the previous title

            dispLeft += lblArray[i].Width;
        }
        // panel length&#12288;<= total length

        //    of titles - length of the longest title (cyclic formula)

        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:

// moving news title labels on each timer tick 

private void timer1_Tick(object sender, System.EventArgs e)
{
    for(int i = 0; i < lblArray.Count; i++)
    {
        lblArray[i].Left -= 1; // move to the left 1 pixel per tick


        // each title cycling on panel from right to left 

        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&#12288;<= 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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here