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

.NET TrayBalloon with hyper-links and fading

0.00/5 (No votes)
17 Nov 2010 1  
.NET C# TrayBalloon component with hyper-links and fading.

Introduction

.NET Framework has a rich set of user notifications, but there is no tray balloon that you can use in message-oriented applications. This article presents you a ready to use component and explains how to customize and use it.

Background

Sometimes when writing user interactive applications, especially those dealing with internet resources, we need to show some information balloons to the user. A MessageBox or a memo in the bottom are not very convenient. The most convenient way of notifications is a tray balloon appearing in the right bottom side of the screen (like in MSN, Skype, and ICQ).

Since I developed this component the first time, it has changed many times to meet all the requirements of its customers. Here is a list of the most significant:

  • It has to be configurable (background, sound)
  • It hast to work with extended desktop
  • It doesn't have to attract input focus when appearing
  • It doesn't have to be displayed in Alt-Tab
  • It has to support hyper links and open a browser when a link is clicked
  • It has to appear stacked on the screen when there are other balloons displayed
  • It has to support the multi-threading async model, dealing with service from any thread (not GUI only)
  • It hast to stay visible when the mouse is in the balloon's region

Key points

I will explain some the most interesting things here.

How to make the tray balloon appear without grabbing the input focus

It's really inconvenient when you're typing some text in a program and a balloon appears grabbing the input focus. We will get this bad behavior if we use the regular Form.Show method. To show a balloon without changes in the input focus, we have to deal with the PInvoke ShowWindow method.

[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, 
              int x, int y, int cx, int cy, int flags);

SetWindowPos(Frm.Handle, (IntPtr)(-1), 0, 0, 0, 0, 0x50);

In the snippet above, I call the native Windows API function to show our window on the top of the screen, above any window. Additionally, according to the last parameter, it will be shown without activation. That's what we need. So, the user typing some text will not be redirected to our window.

How to parse input text and create hyperlinks

To setup a LinkLabel with multiple links is very easy, and described in MSDN in detail. But we need to do that using HTML text in the input (we should be able to copy a link from somewhere and just paste it in the .config file or whatever, and this code has to be parsed and all <a> tags should be converted into links). The most optimal way to do this task is to use Regular Expressions. Usually, Regex can solve text-based problems in the most elegant way than any code-based alternatives. Thus, we just use Regex to parse text and strip all <a> tags, and then we use them as links in the LinkLabel control.

static readonly System.Text.RegularExpressions.Regex A = 
    new System.Text.RegularExpressions.Regex(
            "\\<a\\w+href=\"(?<href>[^\"]*)\"\\W*\\>(?<text>[^\\<]*)\\", 
            System.Text.RegularExpressions.RegexOptions.IgnoreCase | 
            System.Text.RegularExpressions.RegexOptions.Multiline);

        private void SetupText()
        {
            TitleLabel.Text = Title;
            string msg = Message ?? string.Empty;

            var matches = A.Matches(msg);
            if (matches == null || matches.Count == 0)
            {
                MessageLabel.Text = msg;
                MessageLabel.LinkArea = new LinkArea(msg.Length, 0);
            }
            else
            {
                StringBuilder sb = new StringBuilder();
                int last_index = 0;
                foreach (System.Text.RegularExpressions.Match match in matches)
                {
                    var href = match.Groups["href"].Value;
                    var text = match.Groups["text"].Value;

                    sb.Append(msg, last_index, match.Index - last_index);
                    MessageLabel.Links.Add(new LinkLabel.Link(sb.Length,
                        text.Length) { LinkData = href });
                    sb.Append(text);
                    last_index = match.Index + match.Length;
                }
                if (last_index < msg.Length)
                    sb.Append(msg.Substring(last_index));

                MessageLabel.Text = sb.ToString();
            }
        }

How it works

After you've created and adjusted the TrayBalloon object, you should display it calling the Run method. This method will return immediately because it is designed to be used from multiple threads which want to notify the user, not interact with them. Once you've called this method, you can continue execution and not care about how it works.

Now, let's look at the key steps that TrayBalloon passes through. First of all, it queues form show into the thread pool. After that, the thread pool thread calls the main entry point of the TrayBalloon form. In this method, TrayBalloon checks for other visible instances to choose free space in the screen (remember, it has to be stacked on the screen). If there are no other instances, it is shown at the bottom; if there are other TrayBalloons already displayed, it will choose a free space between or above them. If there is no free space in the screen, it will just overlay the top most TrayBalloon widow. Also, when appearing, it uses animation and fading (however, this can be skipped, depending on settings that you may use before show).

TrayBalloon keeps itself on the screen for a few seconds and the animation starts disappearing. However, if the user keeps the mouse above the form, it will not be hidden. After the TrayBalloon is hidden, it unregisters itself in the visible queue to free space in the screen and lets other TrayBalloons to reuse its space.

This is a very brief description of the internal infrastructure; please read the source code for more detailed understanding of how it works.

Result

Here is the test application that can be used to learn more about the TrayBalloon.dll component.

tester.JPG

Here is the resulting customized balloon window:

trayballoon.JPG

Points of interest

During testing of many apps with tray balloons (not just this one), I've accidentally found a very interesting bug. If you make the Windows Taskbar editable and re-attract it to another corner of the screen when the tray balloon is appearing, Explorer may hang up :) Be careful.

Before using this component, we need to setup some properties such as Title, Message, etc. Look at the form sample to see the required minimum set of fields to be set. If you need to specify some sound when it appears, or a custom background, please do it. There are many other different tweaks that can be applied to obtain performance, beauty, and so on.

History

This is the initial version of the article. Any new improvements will be posted here in future.

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