Jim's Software |  Jim and Katrin

Random development notes

Pixel Snapping a DrawingVisual

11/13/2008  8:35 PM

image I’m drawing using the XSnappingGuidelines and YSnappingGuidelines to sharpen the edges of some lines in my 2D model. The usage of these was not entirely obvious to me from the documentation. Here it it in short:

A horizontal or vertical edge that falls on a guideline is snapped to the nearest pixel. The line is then filled away from the snapped edge to the pen thickness, blending for non-integers.

Edges and guidelines are both double values, and neither needs to fall on an integer value for snapping to occur. This can lead to some interesting effects.

The top section of lines in the image to the right are all drawn with a pen of width 1.0. The bottom lines are drawn with a pen of width 1.5. The lines are staggered by 0.1, so they don’t fall on pixel boundaries.

The columns are as follows:

  1. No snapping guidelines
  2. Snapping to line y position + 0.2
  3. Snapping to line y position
  4. Snapping to bottom edge of line
  5. Snapping to top and bottom edges of line

Option 4 is what we’re usually going to be looking for. This ensures that one edge is sharp, and all lines are drawn with consistent widths. In the case of integer width pens, this means two sharp edges. Of course this causes uneven spacing between lines, but that should rarely be this obvious.

Option 5 produces weird effects with the non-integer (1.5) pen; since both edges are snapped, the pen width is rounded to the nearest integer, and not consistently, resulting in lines with width 1 or 2. So this method makes the line thickness depend on the line position – probably not what you’re going for unless you want two sharp edges on a very thick line. 

Option 3 is what I would have expected to use; this causes the line to straddle the guideline. It always produces a symmetric line, and if the pen width is an even integer, it results in snapped edges

Option 2 is interesting; it causes the lines to draw consistently, although neither edge actually falls on the guideline. I’m not sure what the logic is here, and it seems that this could cause guidelines to affect shapes that they aren’t meant for.

Example project (Visual Studio 2008, .NET 3.5)

Static Members on Generics

10/24/2008  10:01 PM

I’m currently porting a library from Java to C# that relies heavily on generics. In the process I’m finding out all sorts of interesting things about generics in C#, including this tidbit:

A static member of a generic class has one instance per closed generic type, NOT one instance for the overall type definition.

So for instance if you have:

public class BadGeneric<T>
{ 
    public static Dictionary<int, string> stuff = new Dictionary<int, string>();
}

and you instantiate instances of this with different type parameters:

BadGeneric<int> test1 = new BadGeneric<int>();
BadGeneric<int> test2 = new BadGeneric<int>();
BadGeneric<string> test3 = new BadGeneric<string>();

you might think you would have one instance of the dictionary - and you would be wrong. The first two share a dictionary, but BadGeneric<string> is a different type, and gets its own separate instance of the dictionary!

Don’t be confused by the fact that Dictionary is itself generic; this happens with all static members, regardless of type. Dictionary is a likely example because it’s the sort of thing you might want to add to in constructors and access across all instances of BadGeneric<>.

Now what?

One solution, explained with much preamble here on CodeProject, is to wrap the static member in a non-generic class, defined separately:

public class GoodGeneric<T>
{
    public static Dictionary<int, string> stuff
    {
        get { return GenericStaticState._stuff; } 
    }
}

internal class GenericStaticState
{
    public static Dictionary<int, string> _stuff = new Dictionary<int, string>();
}

Another possibility is to derive the generic class from a non-generic base:

public abstract class NonGenericBase
{
    public static Dictionary<int, string> _stuff = new Dictionary<int, string>();
}

public class Generic<T> : NonGenericBase
{ 
    public static Dictionary<int, string> stuff
    {
        get { return _stuff; }
    }
}

I think the first is probably a little cleaner, unless you’re using a non-generic base anyway, or an interface that could be converted to one. But don’t see any particular weaknesses with either method.

Remote Desktop With a USB Key

8/13/2008  4:43 PM

Our client has given us a copy of their old software, which requires a USB key to run. I'm 300 miles away. Here's the trick to using Remote Desktop in this scenario (run at a command prompt):

mstsc -v:servername /F -console

Presumably this would also work with other kinds of dongle. What you're doing is connecting to the console session. The caveat is that this only works if the host machine is Windows Server 2003. If you don't have that sitting around, then you can also use RealVNC.

HttpWebRequest 401

7/22/2008  10:12 AM

Getting data with HttpWebRequest is straightforward, until it isn't...

My program stopped working recently, returning a 401 unauthorized from my request. I knew I was sending the right credentials.

A random newsgroup thread tipped me off to the solution:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Credentials = CredentialCache.DefaultCredentials;
request.Accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, " + 
    "application/vnd.ms-excel, application/vnd.ms-powerpoint, " + 
    "application/msword, */*";
WebResponse response = request.GetResponse();

The key is setting the Accept property; I wasn't doing that before. I don't know what happened on the server that makes it now require this header, but now it works...