Skip to content

Iloggable

System.Windows.Forms.ListBox bug with BeginUpdate()/EndUpdate()

Came across an annoying bug with ListBox. If you use BeginUpdate() and EndUpdate() and only add a single item to a cleared Item collection, then that Item does not show up on Refresh. However if you leave the BeginUpdate()/EndUpdate() out, it works fine, resulting in a need for code like this:

listBox.Items.Clear();
if( itemList.Count > 1 )
{
    //only use the Begin/End cycle if we have more than one item
    itemList.BeginUpdate();
}
foreach( object item in itemList )
{
    listBox.Items.Add(item);
}
if( group.Strings.Count > 1 )
{
    //only use the Begin/End cycle if we have more than one item
    mStrings.EndUpdate();
}
listBox.Refresh();

Image Clipping and Alignment with CSS

The clip attribute in CSS is not what I would call the simplest to understand. Never mind that the rect() function uses a space separated list instead of a comma separated one, but that some browsers still understand comma separated. But the ordering of the clip rect of top right bottom left is just bizarre. Finally to understand what clipping does, it's important to realize that the clip rect defines a rectangle of what will be shown, defined from the origin, but it does not affect positioning of the image, which still starts at the origin, clipped areas not withstanding.

log4net filepaths and how to get at Appenders at runtime

Just a note of something simple and silly enough that I shouldn't forget it again: Filepaths in log4net configurations still have to escape the DOS separator backslash. I know it should be obvious, you use \ in a text file, you escape it.

Well, i was too used to the @"c:\foo\bar.txt" syntax from C# that when i took the path out of the code and into the log4net XML config, i left it in the c:\foo\bar.txt format. I wasn't able to wrap a debugger around the deployed code and couldn't figure out why my logger wasn't writing. I figured out how to get to the currently available appenders at runtime and wrote that to the web page trace and seeing that there was no filename for the RollingFile appender, smacked me in the head with the "escape the backslash, stupid".

The silly part out of the way, this did give me some useful insight into log4net internals. So to get at the configured appenders you can do this:

// Just grabbing the first logger, since we want to use it to grab it's parent,
// the root logger
log4net.Repository.Hierarchy.Logger logger
    = (log4net.Repository.Hierarchy.Logger)log.Logger.Repository.GetCurrentLoggers()[0];
Console.WriteLine("Logger: {0}",logger.Name);
//
foreach( log4net.Appender.IAppender appender in logger.Parent.Appenders )
{
    Console.WriteLine("  Appender: {0}",appender.Name);
    // just checking for RollingFile here, but could just as well check for all other appenders
    if(appender.GetType() == typeof(log4net.Appender.RollingFileAppender))
    {
        log4net.Appender.RollingFileAppender rolling
            = (log4net.Appender.RollingFileAppender)appender;
        Console.WriteLine("    Rolling File: {0}",rolling.File);
    }

Mind you this is just a place to get started from. It does make a number of assumptions you shouldn't make in production code. It is good enough though to help you debug log4net behavior.

IE compatibility

Quirksmode is a very useful site regarding javascript and css compatibility across browsers. Using the snippet regarding mouse coordinates, both of the pages mentioned in the last two posts now work in IE as well.

Trigonometry and Javascript

Had some fun this weekend playing with Javascript, trying draw dynamic lines. Since Javascript doesn't actually have any kind of Draw() or Paint() methods, it comes down to manipulating images. I originally started by scaling images of lines, but even after adding a bunch of variations of lines for different lengths and angles, it always looked damn ugly.

Finally I decided to go the traditional line drawing way: One pixel at a time. Well, almost.. i have tiny segments with lovely alpha blurred edges and created them in horizontal, vertical and the two diagonal variations. And i create dashed lines from them, calculating points along the line.

The current state of this experiment can be found here. (Note: This does not work in IE right now. Really only because i didn't put in the alternate code for finding the mouse coordinates, so i'll fix that in time).

Next, time to play with XmlHttp and generate finalized line segments on the fly and place them, as well as save the information so you can recall the paths drawn. Then, I'll look into emulating the google maps code for panning the background around and bringing in offscreen content on the fly.

Atomic file replacement

A traditional way for overwriting a file atomically is to write the new file to temp file, and then use move to replace the original with the new. That way the replacement is atomic and no script that relies on the file existing and being complete will ever fail.

File.Move() in .NET is not the tool for this job. It'll throw an IOException because the destination exists, and there isn't an alternative way of calling it. You can delete the destination first, but then anyone relying on the file existing is screwed. Worse, someone might still try to re-create the file.

However, File.Copy(), does have an alternative overload that let's specify a bool to determine overwriting behavior. This way, the file will always exist, although someone could try to read it in an inconsistent state. And it's an ugly solution if the file is large. Grrrr...

Any better solutions out there?

Emacs, Nxml-Mode and Unicode

I've run into this too many times and fixed just as many.. grr. And i always forget.. Time to write it down.

I use James Clark's excellent nxml-mode to edit pretty much anything that's vaguely XML, i.e. i usually convert HTML i have to edit into XHTML so i can use this mode.

Problem is, if you just start writing XML in that mode, the resulting file will be Unicode encoded. There is a fix to this. Write proper XML :) Basically, first add this to your .emacs file:

(unify-8859-on-decoding-mode)

Next, make sure you got your proper XML header:

<?xml version="1.0" encoding="utf-8"?>

Tada! File is saved in proper form.

Just to be all proper and stuff, I use this header for my html/xhtmlL

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">

Asynchronous Postback in Web Applications

So a while back I read an an article about the Client Callback Feature in ASP.NET 2.0, which allows ASP.NET 2.0 to do updates to a page without a full page rountrip to the server. But wouldn't you know it, it was specific to Internet Explorer. The article ended on a hopeful note with:

Please note that not every browser supports client callbacks, so two new boolean properties named SupportsCallback and SupportsXmlHttp were added to the Request.Browser object. Currently, both properties will return the same value, but the two properties were created because client callbacks might be implemented using a different technique other than the XMLHTTP ActiveX object in the future.

2.0 is still not out, but cross-browser support using XMLHttpRequest is certainly possible to anyone wanting to roll their own code. A very nice example of this can be found here.

ASP.NET 2.0 isn't out yet. So i figured, i might as well see if the stance for Client Callbacks and cross-browser support has changed since that first article. Info was only vague, but i think the answer is indeed maybe? -- at least if this blog post is favorably interpreted... Although this blog did not interpret it as such...

If it's not in there, I'm sure going to find out how hard it would be to subclass the appropriate classes to create a W3C XMLHttpRequest capable version

Tweaking ContextMenu's for List Items

A little System.Windows.Forms diversion. One thing that's ill-documented, imho, is the CheckedListBox. And if you then want to add a context menu that's context sensitive to the Item in the list you are over, then good luck finding any useful info. Therefore, I figured i put this snippet in here before I forget again how do deal with this.

The best example I found for handling ContextMenu in the context of a list item recommended completely ignoring the ContextMenu property on the listbox and handling it all in the MouseDown event--creating the context menu on the fly and all.

That seemed a little overkill to me since all i wanted to to do was disable the one item Edit on the context menu. So, instead i capture the Popup event and tweak my menu there. First the setup of the context menu (in my constructor):

ContextMenu contextMenu = new ContextMenu();
MenuItem edit = new MenuItem("Edit");
contextMenu .MenuItems.Add(edit);
edit.Click += new EventHandler(edit_Click);
contextMenu .Popup +=new EventHandler(contextMenu _Popup);
checkedListBox.ContextMenu = contextMenu;

And here's the popup handler:

private void contextMenu_Popup(object sender, EventArgs e)
{
    //don't forget to translate the mouse coordinates to the control local coordinates
    int index = checkedListBox.IndexFromPoint(checkedListBox.PointToClient(MousePosition));
    if( index == -1 || !checkedListBox.GetItemChecked(index) )
    {
        ((ContextMenu)sender).MenuItems[0].Enabled = false;
    }
    else
    {
        ((ContextMenu)sender).MenuItems[0].Enabled = true;
        //storing the index in a class field so that i don't have to
        //do the math again and in case the mouse moved
        contextSelection = index;
    }
}

So there you have it.