Introduction
This article is about the construction of an RSS reader UserControl, and is my first contribution to CodeProject. I will show you through the development of this reader, explaining how to create a User Control with the C++/CLI using the .NET 2.0 framework.
Project Creation
First, you have to create a new CLR / Windows Forms Control Library project. I'll name it rssFeeder. Visual Studio 2005 will generates a class, that derives from System::Windows::Forms::UserControl
.
public ref class rssFeederControl :
public System::Windows::Forms::UserControl
The form rssFeederControl.h will represent our control. It's empty for now. Before filling it, we'll first talk about RSS quickly, and then about the properties of a UserControl.
Some words about RSS
RSS is used for syndicating a structured page, like a blog. We use an XML that describes the page. A sample page will look like this:
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" [...]>
<channel>
<title>Title of the blog</title>
<link>http://url.of.blog.com</link>
<description>This is the description of the blog.</description>
<item>
<author>Me</author>
<title>The last news</title>
<link>http://url.of.blog.com/?news=2</link>
<description>Description of the news</description>
</item>
<item>
<author>Me</author>
<title>The first news</title>
<link>http://url.of.blog.com/?news=1</link>
<description>Description of the news</description>
</item>
</channel>
</rss>
We can have an XML feed, for the comments too, the format is quite the same.
I will create a class (in fact, two classes) to load the content of the XML.
ref class CRssObject
{
public:
CRssObject(void);
String ^ title;
String ^ link;
String ^ description;
String ^ language;
System::Collections::ArrayList ^ listItem;
bool LoadFromUrl(String ^, int, String ^);
bool LoadFromFile(String ^, int, String ^);
private:
bool isRssVersion2(Xml::XmlNode ^);
String ^ GetText(Xml::XmlNode ^, String ^);
bool LoadObject(Xml::XmlDocument ^, int, Xml::XmlDocument ^);
};
ref class CItemRss
{
public:
CItemRss(void);
String ^ author;
String ^ title;
String ^ link;
int nbComments;
};
I will construct an RssObject
from an XML URL (or file). I will load only elements that I want to use, for example the title and the link. This object can be loaded only if the RSS version is 2.0.
You can look in the sources files to know how I'm loading the object from XML; as an example of code, I'm using the HttpWebRequest
object to read XML from a URL.
HttpWebRequest ^ HttpWReq =
dynamic_cast<HttpWebRequest^>(WebRequest::Create(url));
HttpWReq->CachePolicy =
gcnew Cache::HttpRequestCachePolicy(Cache::HttpRequestCacheLevel::Reload);
HttpWResp = dynamic_cast<HttpWebResponse^>(HttpWReq->GetResponse());
sr = gcnew StreamReader(HttpWResp->GetResponseStream());
Xml::XmlDocument ^ xml = gcnew Xml::XmlDocument();
xml->LoadXml(sr->ReadToEnd());
In the CPP file, you will see my own method that finds out how many comments there are on the news. As I didn't see any specifications for this, I looked for the URL of the news in the URL of the comments. If I find it, I get a comment.
Attributes
Existing common controls (button, checkbox, etc.) already have some properties, like visible
, size
, location
, .... This control has those default properties too. We are now going to add some extra properties to our control. We will add as properties, the URL of the XML file, the number of news to display, and the delay for refreshing the control. We will add the URL of the comments as an optional property.
To create a property, add this code:
[Category("Configuration")]
[Description("Type here the Url or the xml")]
property String ^ url
{
String ^ get() { return url_; }
void set(String ^ value)
{
url_ = value;
refreshControl();
}
}
We use the Category
attribute to name the field where the property will be put (if this attribute is not specified, it would be put in the Misc. category). We use the Description
attribute to display a description when clicking on the field. Now, by adding our control to the toolbox and by drawing the user control on a form, we will see this in the property windows:
A property can only be a string! Here, the types of my properties are simple (string
, int
etc.). For complex types, use a TypeConverter
.
Creation of the control
As we will not know before the configuration, how many news to display, we will construct the form dynamically. We will use a control box and a cli:array
of LinkLabel
s. See this in the source code.
Add a personal image to the control
By default, the image for the user control is a wheel. We may want to add our own image. It's very simple in C#, but with C++/CLI, you have to follow these instructions:
- add
[ToolboxBitmap(rssFeeder::rssFeederControl::typeid)]
before your class.
- Create a 16x16 bitmap.
- Name it as follows: Namespace.ClasseName.bmp.
- Add it as a resource: Right click on project --> Add --> Resource --> Import (bitmap).
- Link it with the DLL. Right click on the project --> Properties --> Linker --> Input --> Embed Managed Resource File, and add the name of the bitmap.
Events on the control
We may want to do a particular action when we click on a link (for example, when browsing the URL). The user then should intercept the Click
event on a LinkLabel
item. To do this, we have to create a delegate:
delegate void ItemClickHandler(Object ^ sender,
LinkLabelLinkClickedEventArgs ^ e);
Then we have to add this event to the configuration category:
[Category("Configuration"), Browsable(true),
Description("Event raised when clicking on an item")]
event ItemClickHandler ^ itemClick;
And raise the event when clicking on a LinkLabel
. For this, during the user control creation, we add a Click
event handler on each LinkLabel
, as follows:
linkLabel->LinkClicked += gcnew
System::Windows::Forms::LinkLabelLinkClickedEventHandler(
this, &rssFeeder::rssFeederControl::linkLabel_LinkClicked);
Then, we just have to do this to raise the event:
void linkLabel_LinkClicked(Object ^ sender,
System::Windows::Forms::LinkLabelLinkClickedEventArgs ^ e)
{
if (&rssFeederControl::itemClick != nullptr)
itemClick(this, e);
}
Finalizing the control
This is the main part. Don't hesitate to finalize the control, for example, I've overridden the Paint
method to measure the string, to avoid the LinkLabel
being larger than the control. I've added the output of the number of comments (if I can load it), and a tooltip on the LinkLabel
with the author.
You can use the attribute DefaultValue("Default value")
for setting a default value. I've done this in the constructor.
Conclusion
With this article, you should now be able to create a user control. In the Zip files, you will find the complete source code and the binaries of the user control and the project demo. Don't hesitate to send me feedback about this control or this article.