Friday, October 29, 2010

flash.net.FileReference (Action Script 3.x)

I recently had the chance to work in Action Script at my job. I had not worked in Action Script previously but was encouraged as the language is a mix of JavaScript and C#/Java (two languages I am reasonably comfortable with). One of the tasks I tackled was backing up data to the hard drive using FileReference. FileReference is a simple way to access the file save and load functionality within a browser or otherwise. I was able to do some fairly neat things such as serializing objects and saving/loading them in a binary file. Writing XML to a file was simple. Action Script has a good amount of XML processing functionality (although sometimes a bit confusing to someone new to it) so reading the file back in was no problem. FileReference takes care of the save/load dialog and works with callbacks. It is clearly geared towards pushing the developer to make a decent user interface that doesn't lock up the render thread. (many developers don't seem to care about this kind of thing!)

FileReference (Adobe livedocs)

Thursday, October 28, 2010

Graphics.DrawString vs. Path.AddString

In my Card Maker application I recently added support for drawing elements / text with an outline. Unfortunately in doing so I ran into a major difference in the scale at which Graphics.DrawString and Path.AddString draw. The scale of the font drawn by Graphics.DrawString is about 4/3 the size of one drawn by Path.Addstring

(... removed old terrible solution ...)

My original solution to the problem was a hack using a magic value. You should be looking at the Font.Unit and checking if it is GraphicsUnit.Point. If so then should be converting the font size to the EM size like so:

Graphics.DpiY * (zFont.Size / 72f)
  
If the Font.Unit is another value you should research further. Thanks to Mike Garrett for his comment. The documentation for the GraphicsUnit.Point (and other values) on MSDN reveals some of the mystery.

Wednesday, October 27, 2010

Dictionary (.NET C#)

The System.Collections.Generic.Dictionary is incredibly easy to use. It helped me clean up some of the most excessive casting in my history as a coder. My early days of Java and C# had a lot of terrible looking code with lots of mystical casts on objects pulled from Hashtables. The haphazard casting of objects is not exactly desirable. It is a necessary evil at times, but clearly known key and value types in a Hashtable type data structure should not be one of those necessary evils.

Bitmap zBitmap = null;
string sKey = sFile.ToLower();
if (s_htImages.ContainsKey(sKey))
{
  zBitmap = (Bitmap)s_htImages[sKey];
}
Bleh...

Tuesday, October 26, 2010

Graphics.MeasureString (.NET C#)

After testing out various situations for scaling the font of a string to fit the text within a given Rectangle I finally settled on Graphics.MeasureString. There is a cpu hit to performing the measurement, but if you can limit the number of times you need measure it is worth it. The code below is from my Card Maker application. It handles adjusting the font size based on the size of the target Rectangle.


SizeF zSize = zGraphics.MeasureString(sInput, zFont, new SizeF(zElement.width, int.MaxValue), zFormat);
 
if (zSize.Height > zElement.height || zSize.Width > zElement.width)
{
  float newSizeRatio = 1f;
  if ((zSize.Height - zElement.height) > (zSize.Width - zElement.width))
  {
    newSizeRatio = (float)zElement.height / (float)zSize.Height;
  }
  else
  {
    newSizeRatio = (float)zElement.width / (float)zSize.Width;
  }
 
  Font scaledFont = new Font(zFont.FontFamily, newSizeRatio * zFont.Size, zFont.Style);
  zFont = scaledFont;
}

Notes:
  • zElement is an object containing the target width and height.
  • The ratio can differ due to the need to keep the text within the Rectangle. Drawing outside of the target Rectangle would defeat the purpose!
  • The int.MaxValue may seem strange but the height of the allowed Rectangle (to measure within) is not important to me. The text being tested by MeasureString is formatted to line wrap.

Monday, October 25, 2010

TryParse (.NET C#)

Back in the old days of .NET 1.x it was common to have this sort of code to convert a string into an int variable:


int x = 0;
try
{
x = int.Parse("bad");
}
catch (Exception)
{
    //...
}

While the code above was effective it required a try catch to handle errors. As of .NET 2.x there is a TryParse method in addition to the original Parse method on a variety of types. The code is a lot simpler. The return value of TryParse is a bool so your code can be a little less messy. Wrapping things in an if statement is a lot better than a try/catch for a variety of reasons.


int x = 0;
int.TryParse("bad", out x);

MSDN Int32.TryParse

Friday, October 22, 2010

XSD.exe (.NET)

To me XSD.exe is a tool for generating a code file for representing code accessible XML data. There are a variety of other uses but that is the one I have actually setup in projects. The generated code is also setup in a partial class so it is easy to expand upon the functionality of a given XSD based object. I generally build my XSD schema file and then use the pre-build event to invoke XSD.exe to generate the code file representing my objects. While XSD.exe/generated code usage may not always be the most appropriate, especially if your schema is not set in stone... It is a powerful tool to have accessible objects from XML with minimal setup time.

MSDN XSD (VS 2005)

Thursday, October 21, 2010

PropertyGrid (.NET C#)

The topic today is simply the PropertyGrid. While to many this is nothing new nor very exciting. But if you have been writing applications without knowledge of the PropertyGrid control now is the time. Go forth and investigate. The PropertyGrid allows you to assign an object and not only view but edit the properties of an object. It makes debugging and tweaking incredibly easy. There are some disadvantages though. You cannot cycle through values, instead you must commit each change by pressing enter or leaving the control. Below is an example of a property exposed from an object with just the bare essential properties. The description to display in the PropertyGrid for the Thickness property is defined with the DescriptionAttribute.


[DescriptionAttribute("Border Thickness (0 is fill)")]
public int Thickness
{
get { return m_nThickness; }
set { m_nThickness = value; }
}


You will need to do a little research on the various attributes you can apply to your properties. Some basics are: 
  • CategoryAttribute
  • DescriptionAttribute 
  • BrowsableAttribute 
  • ReadOnlyAttribute 
  • DefaultValueAttribute 
  • DefaultPropertyAttribute
To assign an object for viewing/editing just assign your PropertyGrid.SelectedObject value the desired object. There are of course events associated with the PropertyGrid as well so you can catch value changes. The only application I have used a PropertyGrid for so far is my Card Maker application. I will definitely consider it in any future projects or those I revisit.

Wednesday, October 20, 2010

Drawing Text with Ellipsis (.NET C#)

Although I have not used it extensively, the StringFormat.Trimming functionality could come in handy in many situations. This will change the way Graphics.DrawString renders text within the destination rectangle. You can specify a visual indicator to the user that the text contents are larger than the rectangle it is being drawn within. Based on the StringFormat.Trimming setting the behavior will differ.

StringFormat stringFormat = new StringFormat();
stringFormat.Trimming = StringTrimming.Character;
stringFormat.Trimming = StringTrimming.EllipsisCharacter;
stringFormat.Trimming = StringTrimming.EllipsisPath;
stringFormat.Trimming = StringTrimming.EllipsisWord;
stringFormat.Trimming = StringTrimming.None;
stringFormat.Trimming = StringTrimming.Word;
(Note: The above is just a list of possible settings... please do not write code like this ever)
Unfortunately there is no indication, other than the obvious visual, that a string was truncated. I am still investigating solutions to determine if the text will be cut off by the destination rectangle. Graphics.MeasureString is far from fast and Graphics.MeasureCharacterRanges seems to be a bit of a mystery thus far. This will likely become a later topic unless I just forget about it...

Tuesday, October 19, 2010

ScrollableControl and Panel: Mouse Scroll and Draw (.NET C#)

The ScrollableControl class is great if you are creating a control that will need to display the scroll bars vertically and horizontally. The Panel control does the same with the controls added to it. Unfortunately, by default, when you drag the scroll bar with the mouse the rest of the control does not draw until you let up on the mouse button. In every application I have created I have never wanted this behavior. I finally took some time to investigate and found 1 magical line of code. Followed up by 5 further magical lines of code.


SetScrollState(ScrollableControl.ScrollStateFullDrag, true);
 
public static void SetupScrollState(ScrollableControl scrollableControl)
{
 Type scrollableControlType = typeof(ScrollableControl);
 MethodInfo setScrollStateMethod = scrollableControlType.GetMethod("SetScrollState", BindingFlags.NonPublic | BindingFlags.Instance);
 setScrollStateMethod.Invoke(scrollableControl, new object[] { ScrollableControl.ScrollStateFullDrag, true });
}

SetScrollState on MSDN
ScrollStateFullDrag on MSDN

By enabling the ScrollStateFullDrag your control will hit the OnPaint event each time the scroll value changes. Though beware... there is one minor issue I ran into. The state of the flag appears to be reset each time the size of the scrollable control changes. In my case each time I changed the AutoScrollMinSize I just called SetScrollState again.

The second block of code (the SetupScrollState method) is a bit more back door approach to setting up the ScrollStateFullDrag on your ScrollableControls. I found a good post by someone by the nickname dpuza (forum link) indicating an approach by which to call the protected SetScrollState method in your ScrollableControl. It works well, though you may feel a bit wrong making the reflection call... This is one approach to setup your existing Panel control to draw and scroll without creating a new PanelEx type of class.

Monday, October 18, 2010

User Controls: Double Buffering (.NET C#)

I figured I would jump right into things... but it is my first post so I figure I should explain the subject matter. This blog is dedicated to things I have learned while coding. I am primarily a C# programmer that is slightly behind the times. I am still enjoying .NET 2.x.

Now on to the topic of the day: Double Buffering User Controls

I had an old block of code to copy-and-paste around that performed double buffering manually. It created a back buffer to draw into and improved the problems with flickering in my applications. It worked reasonably well. Fortunately my old block of code was made obsolete by 4 lines of very powerful code. (it could be 1 with ORs)

   1:  SetStyle(ControlStyles.AllPaintingInWmPaint, true);
   2:  SetStyle(ControlStyles.UserPaint, true);
   3:  SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
   4:  SetStyle(ControlStyles.Opaque, true);

ControlStyles Enumeration at MSDN

  • AllPaintingInWmPaint and OptimizedDoubleBuffer are actually required together based on the documentation. 
  • Opaque eliminates any background drawing. Depending on your application you may want a background.
  • UserPaint turns over paint responsibility to the control.
The performance actually improved quite significantly over the old manual double buffering. Plus my code is much simpler and ever-so-slightly more logical.