Archives

Archives / 2005 / May
  • LinkBox - Fun with Panels, LinkLabels and AutoScroll

    Remark: This is a spin-off of my work on GhostDoc. As the control I wrote for GhostDoc is highly specific to the actual problem I wanted to solve, I’ll only explain the basic idea and provide the source for the “LinkBox” control which I use as a base class. For some basic use cases this control may already be sufficient, for other use cases you’ll have to add some code.

    Situation: I need something like this in one of my dialogs:

    20050529_LinkBox1
    (Note this is a mockup inspired by an Outlook dialog,
    not related to my work on GhostDoc)

    Clicking a link raises an event, the event arguments provide information about which link was clicked.

    If necessary, scrollbars appear:

    20050529_LinkBox2

    Question: How do I implement this?

    First thought: Web browser control. Why? Because of the links. Hmm… Do I need any other feature of HTML? No, just the links.

    Second thought: In this case, a web browser control smells like overkill. So what else gives me multi-line text, links and scrolling? A RichTextBox control. While using a RichTextBox for text input (its main purpose) can be a bit frustrating, I’ve had good success in the past using it for output (see this and this post). And you can have links in rich text. By default, only http and mailto links are supported, but that’s a limitation that can be circumvented (see this CodeProject article by “mav.northwind”). Unfortunately, the RichTextBox control’s LinkClicked event only provides the text of the link — which can be a problem when trying to identify which link was clicked.

    Third thought: If I’m able to crank out a user control for my specific needs with little effort, I’d definitely prefer that to using a web browser control. So what’s the simplest thing that would work for me? Do I need multiple links in one line? No. OK, so I can use a LinkLabel control for each individual line (which makes identifying which link was clicked pretty easy).

    The solution: A user control completely filled with a panel (to get the sunken borders), link labels are added dynamically (with auto-sizing enabled) and are docked to the top, so I don’t have to take care of positioning. Scrolling is taken care of by the panel (AutoScroll), the AutoScrollMinSize is easy to determine as the labels are auto-sized (so width = largest width and height = y-coordinate of the last label’s bottom border).

    The code can be downloaded here, complete with a demo project:

    linkBox1.AddText("This is some fixed text");
    linkBox1.AddLink("The quick brown {0}", "fox");
    linkBox1.AddLink("jumps over the lazy {0}", "dog");
    linkBox1.AddLink("This is a {0} with a tag object", "test", "Some tag object");

    20050529_LinkBox3

    As already mentioned, the LinkBox control may be sufficient for simple use-cases. For more complicated use-cases (where you may need updating/refreshing), the control offers a SetText and an UpdateAutoScrollSize method (which in the GhostDoc source are called by a derived control). If you use LinkBox purely as a base class, you should think about making the methods protected — in a derived, application-specific control, you typically specify some sort of “data source” object and the control takes care of keeping the display up-to-date.

    Implementation detail: This control uses docking for its layout, so the z-order of the LinkLabel controls is important. In general, when you add controls docked to the top in the forms designer and look at the resulting code, you’ll notice that the controls are added in reverse order. This reversed order is necessary because of the z-order that influences the docking. To achieve the correct z-order without the adding the controls in reversed order (which would make things a bit more complicated when adding controls programmatically like LinkBox does), you have to set the child index of the control:

    thePanel.Controls.Add(theLinkLabel);
    thePanel.Controls.SetChildIndex(theLinkLabel, 0);

    In the case of the LinkBox control, this leads to the situation that thePanel.Controls[0] does not contain the LinkLabel control representing the first line. This is nothing you usually have to care about, I just mentioned it to avoid confusion in case you dig a little bit deeper in the debugger e.g. when running the demo.

    Download the code

  • "Visual Studio Hacks" Book: Excerpts Online

    Excerpts from the “Visual Studio Hacks” book by James Avery have been published on the OnDotNet web site.

    Unfortunately I didn’t have much time to read the book in the previous weeks. Yesterday was the first day of the year that the local “Freibad” (public outdoor swimming pool) was open, so I took it with me to read it while sunbathing. And I must say that “Visual Studio Hacks” passed my personal “Freibad test”, i.e. it was interesting enough to be read in a noisy environment, with interruptions (kids playing soccer in the sunbathing area), and without a computer nearby. Other books that passed this test in previous years are “C# Unleashed” by Joseph Mayo, “Code Complete 2” by Steve McConnell and the “Extreme Programming Pocket Guide” by chromatic.

    Back to “Visual Studio Hacks”: I consider myself an advanced user of Visual Studio, so many of the hacks are not really new to me, but most of those hacks contained some bit of information I didn’t know yet or completely forgot about. What I really liked about the book is that it’s not a simple collection of tips that the author barely tried himself. You notice that in the little details like the solutions to problems you may not encounter immediately, but will run into sooner or later in your daily work (e.g. the infamous “Call rejected by callee” error). So far I’ve read the first half of the book and I couldn’t find anything that I would consider of little value – I wish could say that about many other computer books.