Sam Allen's profileDOT NET PERLSBlogListsSkyDrive Tools Help

Blog


    Code Moved

    This code and post is now entirely moved to Dotnetperls.com.

    // TODO comments MOVED

    Hey, it's moved to DotNetPerls.com, although it's missing the ads. Sorry!

    FTS3/SQLite Article MOVED

    The new article is at this location

    Customized Dialog/MessageBox in C# and .NET

    There is now a much more complete and detailed article WITH CODE at Dot Net Perls Dot Com--A Customized Dialog...

    Having studied the Windows UI Guidelines (XP, Vista, etc.) I came to realize that I needed greater control over my dialogs than I could get in C#'s MessageBox.Show() method. I also wanted fewer options in place, to eliminate complexity over things I don't use. In Windows, when you present a dialog, you should usually not use an OK button, but use an action verb as the "accept" button. However, MessageBox.Show() won't let me use verbs (anything from "Go," "Proceed," "Agree," to "Acquiesce"). So, I looked for solutions and thought the simplest would be for me to implement my own MessageBox.Show(). Now, I haven't wrapped everything up perfectly and I need to learn more about reusable components, but I am pretty happy with the result so far.

    My dialog supports more options, in particular these:

    • Two buttons that can have any text. If you want to format your disk, you can click "Format." Not possible with MessageBox.Show().
    • Custom icons! I can swap in different icons at any time. Buy a custom icon set? Use it and make your program look awesome! There are plenty of free sets on the Internet. Give your program some pizzazz!
    • It correctly attracts the mouse when the Windows option to snap cursor to "OK" button is selected. (Do other people use that? I can't live without it.)
    • It doesn't beep when it appears. I don't like beeps but this isn't that important.
    • It can be centered on the parent window, or you can even persist the coordinates after the program quits! I just use CenterScreen.
    • It has some crude resizing logic, using a couple heuristics. This works okay but isn't really exact. I can work on this more.

    special-dialog-ss

    Here are some implementation tricks, to try this at home:

    • The white section is a TableLayout. Create a table, give it two columns, and make it cover the top part of the window. Put the icon in the left column, and the label for the text in the right. (There are so many little options to set, but you get the general idea.)
    • Set the background color of the table to white (or 'Window').
    • Put the bottom buttons in the corner.
    • Use a constructor (with initialization lists) to make creating the dialog easier.
    • Insert some simple sizing logic (complicated might be better).

    Then just add the window (SpecialDialog.cs) to your projects, and call it the normal way (you will need to fix namespaces, etc.).

    Please see the new site (link above).

    Rot13 in C#: Moved

    DataGridView’s Secrets MOVED

    I have this post and more "secrets" at DotNetPerls.com. No ads!

     

    SQLite Full-Text Index MOVED

    Post now located at Dot Net Perls Dot Com, HERE.

    Build Macros--MOVED

    See the "remixed" article here. Sorry--I am moving things. The new article is a bit nicer. See you there!

    Dot Net Perls, Developing and DLL Importin’

    What has been developing in the world of Dot Net Perls? Here's some stuff I have been doing:

    C/C++ interoperability. Did you know that using [MarshalAs] is faster than allocating IntPtrs manually and passing them to an unmanaged DLL? Neither did I, but it is. (I also tried changing security settings on the DLL calls, but I need to do more research on that.)

    Make sure your unmanaged declarations look like this:

    [DllImport("...")]

    public static extern int FunctionCall([MarshalAs(UnmanagedType.LPStr)] string a);

    And then call them normally. This was faster than declaring the parameter as an IntPtr and then converting/freeing it manually.

    User-defined controls—some tricky issues here. I tried to name some properties X and Y and it ruined my program—make sure to pick different member variable names. There are a lot of little painting issues I have dealt with, but generally they are not too hard to deal with. (My user-defined control is a board grid, with mouse-hover effects, and different colors.)

    Override methods—these are important. In a user-defined control, use "public override void OnPaint()" to control the painting. Visual Studio will offer a bunch of Intellisense stuff when you type those things. Interesting to look at.

    I have given up on tooltip balloons in .NET completely; they are buggy. Other people have noticed this, too. Just don't do balloons unless you can't help it. They always find a way to fail.

    Read more about C/C++; branch prediction; finite state automata. I am still developing my DAWG (Direct Acyclic Word Graph); I am working on some new applications and am considering putting my code/logic into an open source project. Did more benchmarking.

    Enhanced/rewrote/refactored my MakeDAWG program, which generates a direct acyclic word graph and stores it in file. It is more robust now, and uses my current code to recurse through the trees.

    I don't think I did much with Excel/Word; maybe more on that soon.

    Some other hacking but nothing extraordinary.

    TextBox.AppendText Article MOVED

    Look here for this article. I am moving this site to a much better place. Sorry for the inconvenience!

    Programming Variable Sht--MOVED

    This humor post about variable naming is now located at Dot Net Perls.com. Look at it HERE.

    Windows Forms Progress; Studying More C#

    Here are some things I have accomplished in C# recently:

    1. Worked on a database layer for one of my programs. I am still trying to figure out the best way to separate the database logic from the UI logic. I am using a static class right now.
    2. Studied my C# book and read a couple chapters. Here are some things I took notes on:
      1. Constructor initializers. These make creating contructors less burdensome and more graceful (therefore less prone to bugs). Used this in my QueueCache class.
      2. Abstract classes must be inherited from only.
      3. An interface, such as IDisposable (the I at the start stands for interface), is a contract that a class must implement a set of methods. So it is just a standardization tool that enhances "mashups"—component combinations. ("Mashups" is my word.)
      4. Array.Rank: the number of dimensions in an Array object. Not too useful very often.
      5. Array.LongLength: the length of items in an array as a "long" number. I am not sure I will ever need this.
      6. Array.CreateInstance: a way to make a new Array object of a type determined at runtime. So a function can create an array of type T when called with different arguments. Might be useful.
      7. Null coalescing operator. Is this useful? I think that "x = y != null ? y : z" is equal to "x = y ?? z". Which is better? I like the latter. It improves the clarity of code, but might not be known by an old C programmer. Ternary is more established.
      8. "is" and "as"—I have used these, but didn't really know the details. "is" is a test that returns whether an object is compatible with a type (whether it can be cast to that type). "as" actually does the casting.
      9. Explicit cast features: the checked(...) function looks useful in certain situations. To see if another object can be cast to an "int," do this: "int x = checked((int)otherVal)". An exception will be thrown otherwise.
    3. Actually coding progress:
      1. Am redoing user interfaces I am making to use table layouts. These make maintenance and appearance much easier. They look better quicker.
      2. Made code that is very smart about positioning windows when a program is reopened. It has a good idea where to position your window and at what size. It remembers the previous WindowState, and recalls it. It preserves Size even when Location is off the screen and should be discarded. It uses the actual screen boundaries, not counting task bars and sidebars.
      3. Wrote very defensive database code for SQLite that does Try/Catch for exceptions. This means I know whether a database is valid.
    4. A new user Windows form: I created a "New Database" form/window that allows a user to create a new database. It checks file names for validity and works very well. It creates a new database with System.Data.SQLite, creates a new table, etc. It looks like a stripped-down version of Visual Studio's New Project interface. It uses table layout. I like it.
    5. Next thing I am going to study is delegate functions. I have used these but I want to know more.

    Utility Classes for User Experience; Plural Functions

    I have been working on some cool stuff recently. I have gotten SQLite to a point where I feel capable of doing most things I can think of in it, at least with some effort. I haven't started any more personal projects, and in fact I may have a commercial project to work on soon. Anyways, I have been preparing my coding skills and trying to analyze my progress, and learn how to make that same kind of progress faster in the future. I have written 5 Windows Forms applications, each with a different set of features and a different purpose. One is a reference program with 100,000 definitions; another is a content management system; a third, an image converter and viewer; a traffic monitor; and of course the Scrabble program. The most frustrating thing for me has been having to copy and paste so much code!

    So I have endeavored to refactor my code as much as possible and pull out the universal, frequently-used, clear, and useful code and put it in a separate file that I can simply reference from every project. This has gone well so far. I have this code set up as a class called UserExperience.cs. Here are the functions I have put in the static class so far:

    • BalloonShowAbove(). This function displays a info balloon at a nice position above a control (sent as a parameter). It handles the positioning, which is custom and not done by .NET already.
    • DialogStatementConfirm(). I have studied the professional way of creating dialogs and warnings on Windows, and this function is both a reminder of that form and a convenience. It reduces up to 6+ arguments to two strings. It returns a bool that indicates whether the user wants to proceed with the action or not. This helped me remove 10's of lines of code in a few places.
    • AboutBox(). This is the best—it automates a MessageBox that displays program information. This information is gleaned from the project's setup, and is not specified in my code. I call this function in my other code with one argument, which is the date range and name of the copyright holder. I use some Debug.Assert() statements to validate that this input is correct.
      • What is best about this box is that it uses the correct copyright symbol (c), so I don't have to think about it. I closely verified that the dialog box's layout is industry standard.
    • TextBoxFocusedFirst(). This returns the first focused text box in the form. It uses LINQ but calling this function is easier for me.
    • FontFix(). This simply sets a form's font to something more standard (used to improve the font selection so that Segoe UI and Tahoma are always used when appropriate).
    • GeometryToString(). Converts the current form's coordinates (size and location) to a string that can be stored. This function should be called on a FormClosing/Closed event handler and the setting string should be persisted.
    • GeometryFromString(). Reads from the string saved (by the GeometryToString() function) and sets the current form's coordinates.
    • PluralQuick.Plural(). Takes a singular noun and a count, and returns the appropriate noun.

    As mentioned, a separate class I made is called PluralQuick.cs. It is also a static class, and it offers one function: PluralQuick.Plural().

    static string Plural(string word, int count)

    {

    if (count == 1)

    return word;

    else ... // return a plural form of the word

    }

    I have used PluralQuick.Plural("box", 2) to get "boxes", etc. It works great and improves the clarity of my code. I investigated several solutions for pluralization, and some were either too heavy (complex, bulky) or no better than this one. It would be nice if there was a single, superior solution, but this will work for now. Plural() is quicker than a heavy-duty library and not had to maintain. I throw an exception if the word cannot be pluralized. The function is meant to be only used for a small set of words that are already known (such as those in the UI).

    UPDATE: Look for the code in my public folder!

    System.Data.SQLite Awesomeness

    Okay, enough of that nasty Excel mess. Here's something exciting and cool:

    System.Data.SQLite is a public domain project that aims to build a fast and useful API for SQLite (an amazing and small database engine) that works for C# and .NET. I downloaded the executable, installed it, and after some fiddling and restarting of Visual Studio and some frustration, I put the SQLite code in as a replacement for my own SqliteSharp "hack" (well it is just a really primitive Interop interface). Some benchmarks demonstrated that the System.Data.SQLite system is very fast and powerful. I am quite happy with it. I can use all the knowledge I gained from SQL Server Compact Edition and use it with a better, faster open source project.

    Developing an Unabridged Dictionary in .NET and SQLite

    Using the computer as a reference is extremely handy and can make our lives easier. Sometimes, however, I don't want to read anything in-depth or complicated, or even relevant. I just want to look at random things that pique my curiosity. This is not serious research—it is entertainment. One of the things I have always been fascinated with is obscure or rare words in the English language. There are so many of them—and some of them are so odd.

    On the Project Gutenberg website, an unabridged dictionary from 1913, with about 100,000 definitions and words, is available. The file offered is poorly formatted and contains errors. I used Perl to simplify, clean up, and parse the 40 MB dictionary file. Next, I designed a database structure in which to put these words. I used an SQLite database for instant access and high efficiency. I implemented a clean and pleasant user interface using the .NET framework. Here are some of the features of this program:

    1. Find-as-you-type: the program queries the database instantly on every key press. Definitions appear instantaneously.
    2. Bookmarking: the program allows you to save bookmarks to words or sets of words. Bookmarks can also be cleared.
    3. Persistence: all user data is saved from session to session.
    4. Adaptable user interface: the UI adapts itself to fit your platform (Windows XP, Vista). Fonts are adjusted to look optimal on your system.
    5. Neighboring words: the program will find neighboring words in the dictionary and present them in a combo box. This is done only if it you open the combo box.
    6. Save definitions: it is easy to save a definition to disk (export it).
    7. Right-click lookup: if you see an interesting word in a definition, select it and right-click it to look that word up.

    Those are the 'features.' Here are some of the techniques I used to enhance and polish the program:

    1. Embedded SQLite database: I embedded the SQLite database, known for its small size and extreme speed, into the program. This was done using C++ Interoperability techniques. The result is a database that is extremely fast and responsive, with almost no startup cost.
    2. Multithreaded display: the interface remains highly responsive, as other tasks are run on separate threads.
    3. Paint throttling: an improvement to the display capabilities is a way for the program not to overwhelm the computer with drawing requests. This allows the program to remain responsive and consistent. The algorithm I used is detailed in another post.
    4. Settings and resources: I use the powerful features of the .NET platform to save user settings, including bookmarks. I use the resource manager features to retrieve UI strings.
    5. Extensive text processing. I used a Perl script to format the Webster's dictionary and correct thousands of textual errors and invalid markup. Next I inserted that text into an SQLite database, while preserving almost all formatting.
    6. System-friendly: the dictionary installs with Click Once, so Vista users will not have to give it administrative privileges. It can also be easily removed.
    7. A special class called PluralQuick.cs that returns a pluralized version of a certain word depending on the number of items it refers to.

    There were a lot of "false starts" with this program—here are some of the things I tried and decided against:

    1. Storing the dictionary in any sort of plain text and reading in text files is not optimal—in fact it is slow and uses more RAM. SQLite is the ideal solution to this problem if the data are to be stored on the PC itself.
    2. There are a lot of ways to query an SQL database and have it be very slow—I carefully tested and optimized the queries so that the program responds instantly to any action.
    3. Database layout—the database went through several false starts. Eventually I settled on a system that uses 4 columns—three for words to lookup, and one for each definition. The end database is 27 MB. The original text file was 40+ MB.

    And, finally, here are some things I want to add to the program in the future:

    1. I am already working on adding two new reference sources from Project Gutenberg. These will be put in the same database with no change in functionality.
    2. I think there are more optimizations to do with regards to the SQLite wrapper I wrote and am using. There might also be a better library to replace the one I wrote, although mine has very few bottlenecks and is about 100 lines of code.
    3. Addition of a Direct Acyclic Word Graph for fast word validation: the DAWG data structure I designed in my other programs could be used as an index to the database. This would improve performance dramatically, but the program is already so fast that it might not be noticeable. Perhaps more advanced lists could be presented to the user. I will write in detail about the DAWG in a future post.

    Here are some screenshots of the current version of the Unabridged Dictionary. The user controls are at the bottom of the window. Note how the fonts adjust properly to the different system themes. This is key to keeping the UI looking optimal for (most) users. The program also looks "at home" on XP and performs well on any platform.

    ud-aeroud-classicud-ss1

    From left to right: Windows Vista Aero UI, looking at bookmarks menu, with some definitions displayed (Segoe UI font); Windows Standard (old-school) interface, with Tahoma font, with the neighboring words list open; Aero UI with context menu open, which allows you to look up the selected word. The program can display one or many words at once.

    SQLite Versus SQL Compact: MOVED

    This post has been moved to a new site, Dot Net Perls.com. It is much faster and less annoying than Microsoft Live. See the new article at the new site.