Tuesday, February 24, 2009
Why doesn't MS Word Publish Blog look different?
Wassup wit dat?
How To Show Command Links in a PropertyGrid control
I like PropertyGrid control.
It's really neat.
But it is documented very poorly on MSDN. Once again, .NET Reflector saves the day.
Visual Studio has PropertyGrid controls all over the place, and somehow they got the SelectedObject to show commands on the PropertyGrid command panel.
MSDN does not describe how they did that
Here: "PropertyGrid Class (System.Windows.Forms)" http://msdn.microsoft.com/en-us/library/system.windows.forms.propertygrid.aspx (see CommandsVisible property)
Or Here: "Getting the Most Out of the .NET Framework PropertyGrid Control" http://msdn.microsoft.com/en-us/library/aa302326.aspx
Here I will describe how to get those command links to appear.
See also "why I hate iserviceprovider", (posted feb 20, 2009) on beefycode.com http://beefycode.com/
PropertyGrid control is a black box with a chain of undocumented dependency injection thingies.
A better implementation IMO would have been to expose command links in a PropertyGrid control when the object referenced in PropertyGrid.SelectedObject implements IMenuCommandService. |
Services Services
Command links appear in the PropertyGrid when all these conditions are met:
- PropertyGrid.SelectedObject is set to the instance of an object that implements the IComponent interface
- The IComponent implementation has a value for ISite
- ISite is a service provider, it must provide
- an instance of IMenuCommandService (i.e. your ISite implementation should have a ServiceContainer, and in that ServiceContainer is an IMenuCommandService)
- OR it must provide an instance of IDesignerHost
- an instance of IMenuCommandService (i.e. your ISite implementation should have a ServiceContainer, and in that ServiceContainer is an IMenuCommandService)
- If you are using IMenuCommandService (3.a) then add commands to the IMenuCommandService using AddVerb(new DesignerVerb(…))
The PropertyGrid gets it's commands from IMenuCommandService.Verbs
The DesignerVerb is pretty straight forwards actually, the Text will show up as the link, and clicking on the command link will invoke the Handler. - If you are using IDesignerHost (3.b) …
… yeah … well … good luck with that.
Anyway, according to .NET Reflector, your IDesignerHost will have its GetDesigner(component) method called where component is the selected object instance.
It needs to return an IDesigner instance.
The PropertyGrid gets its commands from IDesigner.Verbs. It needs to be a collection of DesignerVerb instances.
Friday, February 20, 2009
.NET – Application Configuration using XmlSerializer
The ConfigurationManager class provides access to configuration files for client applications. However creating and using a custom configuration section represented by a specific Xml schema is not so straight forwards.
Here I will present a simple way to persist an object as an entire configuration section using XmlSerializer. This implementation does not interfere with other configuration sections, utilizes the ConfigurationManager class to retrieve the section, etc.
Part 1 – The End Result
What this technique going to achieve is the ability to utilize complex application configuration objects in your application in a type safe manner and without all the overhead of properties classes auto-generated by Visual Studio. I will call this application configuration object "ConfigModel" from here on. In the example provided here the ConfigModel object has a string Output property. The application is a console application and all it does is write the value of Output to the console.
using System;
namespace ConfigTest
{
class Program
{
static void Main(string[] args)
{
CustomConfigModel configModel = ConfigModel.GetConfig();
if (null == configModel)
return;
Console.WriteLine(configModel.Output);
}
}
}
Obviously this is a very simple example, but the point is that the confgModel object has a property named Output and the rest of the application should not need any consideration of how to use the configModel object; just assume that it exists (and not that it came from an app.config file).
Part 2 – How Was ConfigModel Created?
The instance of the ConfigModel object in this example is created by deserializing the Xml representation of the configuration section during an implementation of IConfigurationSectionHandler.Create(). Simply put, here's some code:
using System;
namespace ConfigTest
{
public abstract class ConfigModel : System.Configuration.IConfigurationSectionHandler
{
#region IConfigurationSectionHandler Members
public object Create(object parent, object configContext, System.Xml.XmlNode section)
{
if (null == section)
throw new System.Configuration.ConfigurationErrorsException("Configuration failed to load. The config section in null.");
if (string.IsNullOrEmpty(section.ToString()))
throw new System.Configuration.ConfigurationErrorsException("Configuration failed to load. The config section in TestBaseConfigSectionHandler is empty.");
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(this.GetType());
System.Xml.XmlReader reader = new System.Xml.XmlNodeReader(section);
ConfigModel configModel = serializer.Deserialize(reader) as ConfigModel;
return configModel;
}
#endregion
public static TCustomConfigModel GetConfig()
where TCustomConfigModel : ConfigModel
{
foreach (System.Xml.Serialization.XmlRootAttribute xmlRootAttribute in typeof(TCustomConfigModel).GetCustomAttributes(typeof(System.Xml.Serialization.XmlRootAttribute), true))
{
return System.Configuration.ConfigurationManager.GetSection(xmlRootAttribute.ElementName) as TCustomConfigModel;
}
return System.Configuration.ConfigurationManager.GetSection(typeof(TCustomConfigModel).Name) as TCustomConfigModel;
}
}
[System.Xml.Serialization.XmlRoot("ConfigModel")]
public class CustomConfigModel : ConfigModel
{
private string output = "Hello World";
public string Output { get { return this.output; } set { this.output = value; } }
}
}
A few notes about the preceding code:
- IConfigurationSectionHandler on MSDN: http://msdn.microsoft.com/en-us/library/system.configuration.iconfigurationsectionhandler.aspx
- ConfigurationException class (http://msdn.microsoft.com/en-us/library/system.configuration.configurationexception.aspx) was deprecated in .NET 2.0. ConfigurationErrorsException class (http://msdn.microsoft.com/en-us/library/system.configuration.configurationerrorsexception.aspx) should be used instead.
- ConfigurationErrorsException requires a reference to System.Configuration.dll in the project.
- Before C# was bestowed upon man-child, C / C++ was the best programming language ever conceived (IMHO). Someone once showed me a better way to express conditional ("if") statements by putting the constant expression on the left side of the conditional argument to be sure you don't accidentally assign instead of evaluate. The C# language is less prone to this accident (it is not what I think makes C# superior btw).
For example, in C / C++ this perfectly valid: int X = 0; if (X = 1) printf("hello world"); The result here is that you will ALWAYS evaluate to true. … And X will be assigned the value of "1". Some (including myself) consider assignment during a conditional statement a useful feature. Problem is that most of the time I really want to evaluate the condition as "X is equal to 1". What I meant was: If (X == 1) printf("hello world"); Consider the alternative: int X = 0; if (1 == X) printf("hello world"); This does exactly the same thing to evaluate "X is equal to 1", expressing exactly what I meant. However at 4 am the following typo is very common: If (1 = X) printf("hello world"); Fortunately "1" is a constant and a compiler error will let me know that I didn't mean what I said. |
- In the constructor for XmlSerializer I use this.GetType() instead of typeof(ConfigModel) because ConfigModel is abstract and I really want to deserialize CustomConfigModel
- If the name of the configuration section is not the same as the name of the config model class (i.e. CustomConfigModel) then the config model class MUST have an XmlRootAttribute that describes the name of the configuration section.
- There is no requirement for ConfigModel to be abstract, but in the real world it is useful to make ConfigModel reusable, so I made CustomConfigModel to inherit from ConfigModel and describe specific properties.
- The ConfigModel class has a static generic GetConfig() method. There's a little bit of logic in there to assist with getting the name of the configuration section from the XmlRootAttribute of the derived class. I did it this way because I would not want the calling application to figure out the name of the config section; this is just as well because the restrictions about the name of this section are imposed by ConfigurationManager, not by this code example's implementation.
Part 3 – The Application Configuration File
Perhaps the most error-prone part of this solution is making sure the app.config is correct in the configSection, however it is something that is not done very often in development, and there are ways to get visual studio to write these sections for your, or programmatically create / modify application configuration and call the Configuration.Save() method (http://msdn.microsoft.com/en-us/library/ms134087.aspx).
Anyway, the application configuration file needs to define a section and its type. For example:
<?xml
version="1.0"
encoding="utf-8" ?>
<configuration>
<configSections>
<section
name="ConfigModel"
type="ConfigTest.CustomConfigModel, ConfigTest"/>
</configSections>
<ConfigModel>
<Output>Hello World</Output>
</ConfigModel>
</configuration>
Above, the type attribute is telling the ConfigurationManager where to find IConfigurationSectionHandler. The interface could have been put on any class but I just put it in ConfigModel for simplicity.
Also, the <ConfigModel> Xml node is the root of the document used for deserialization. Whatever object types can be expressed by XmlSerializer can be used here.
Summary:
There are a few places where this is very useful. First off is that it's never a good idea to hard-code data into an application. Secondly, implementing your own ConfigurationElement derived classes are painful and impose more specific constraints on how to use those objects.
Maybe in future posts I describe
- more complex ConfigModel derived classes, and how they look in the app config
- using ConfigModel to describe parameters for unit tests (and other unit test stuff like automated unit testing and tests for stored procedures and other SQL objects)
- using IConfigurationSource from the Microsoft Enterprise Library, and the above Xml using a SQL Configuration Source and xml data type
- Using multiple configuration sources and merging config sections (useful when you have very large config files but only need to configure a couple of really small things, or when you have a common configuration for a bunch of applications)
- Configuration editor GUI / loading and saving sections; extending visual studio
Tuesday, February 17, 2009
Testing Pretty Formatter
I got this from Luka Marinko's geek blog (thanks Luka)
http://lukabloga.blogspot.com/2008/10/to-test-new-highlighting.html
static class Program
{
///
/// The main entry point for the application.
///
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new FormMainApplication());
}
}
Sunday, February 15, 2009
XNA / C# – How To Create Full-Screen Graphics Device / Exclusive Mode On Multiple Monitors
When making an XNA game application, it is pretty easy to make your game fullscreen one of two ways:
- The easy way is simply call GraphicsDeviceManager.ToggleFullScreen (http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.graphicsdevicemanager.togglefullscreen.aspx)
- A little bit less easy is to initialize youre GraphicsDeviceInformation.PresentationParameters.IsFullScreen property to true (http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.graphics.presentationparameters.isfullscreen.aspx)
But what if you're making a PC game / Flight Sim / Driving Sim / Dizzying shoot-em-up or whatever and you want to use two or more monitors. A single game window can't span multiple monitors without a deal-breaker of a performance hit (the reason why is a long answer). Does Xbox support multiple monitors anyway?
What you can do is create multiple Game instances, each with their own GraphicsDeviceManager instance, each using a different graphics device. That's the "hard" part – see below.
But wait? For some reason, only one game window will create in exclusive mode. What gives?
Truthfully, I dunno, yet. (.NET Reflector won't expose any answers either)
I made it work this way:
- First I force all graphics devices to create in windowed mode, mapped to different graphics devices
- Second, on the first Game.Update I call GraphicsDeviceManager.ToggleFullScreen()
- Viola! Full-screen XNA presentation on every monitor.
Some may say why bother with full-screen mode if I can just make a windowed mode graphics device big enough to cover the entire screen on both monitors? IMO (without any real proof right now) your 3D Graphics card will perform better in exclusive mode than in windows mode at the same resolution. Probably because the hardware has a lot fewer bits to move around. Even if your $100 nVidia card can move 30GB / sec in graphics RAM, it's gotta be slowing things down somewhere to let windows figure out what to paint.
How to make multiple game windows in the first place
(I'm not posting the code just yet)
- Override the GraphicsDeviceManager class
- In the constructor, hook into the PreparingDeviceSettings event
- In the event handler for PreparingDeviceSettings, set the presentation parameters; be sure IsFullScreen = false and FullScreenRefreshRateInHz is 0 (zero)
- Override RankDevices; remove all devices where the Adapter.DeviceName is not the window you want this graphics device to render on
- In the constructor, hook into the PreparingDeviceSettings event
- Override the Game class
- In the constructor, create your custom GraphicsDeviceManager; be sure you can instruct your GraphicsDeviceManager which graphics device name to use
- In the constructor, create your custom GraphicsDeviceManager; be sure you can instruct your GraphicsDeviceManager which graphics device name to use
- Each Game Window monitors requires its own thread
- In your program startup / main, for each monitor create UI a thread. A couple of good ideas
- Set the thread's IsBackground = false before you start the thread
- Create a ManualResetEvent for each thread and do a try / catch / finally block in the thread function such that in the finally block you set event. This is so that…
- After creating all of the threads, don't let you app quit just yet. Call WaitHandle.WaitAll() with an array of the ManualResetEvent handles for each of the monitor threads
- Set the thread's IsBackground = false before you start the thread
- Create your custom Game object in this Game Window worker function
- The Game object will create a GameWindow (WinForms). You gotta have this thread to handle the message loop. Each form for each window needs its own message loop
- Yes, this means that the GameTime for each of the game windows will be slightly different
Saturday, February 14, 2009
SQL Server DateTime Trick #1
What if you wanted to trim the Time Of Day out of the full SQL DateTime value.
One solution would be to first take the datetime you want to deal with, then convert a string of the combined datepart elements back into a DateTime, like so:
declare @DateFull datetime declare @DateNow datetime set @DateNow = set @DateFull = right('0' right('0' print @DateNow print @DateFull |
Feb 15 2009 11:36PM Feb 15 2009 12:00AM |
Works just fine, but that is an extraordinarily expensive operation. Surely those really smart SQL developers thought about this.
Then I stumbled upon this article: "Temporal Datatypes in SQL Server" (http://www.simple-talk.com/sql/t-sql-programming/temporal-datatypes-in-sql-server/)
Long story short…
print |
Feb 15 2009 12:00AM |
Not only is it easier to read but it will much more reliably give you the correct inclusive beginning of day (not just SQL 2008 either). Use CEILING instead of FLOOR to get the inclusive end of day.
Friday, February 13, 2009
C# Generic Service Provider
I use IServiceProvider all the time. Often times the method calling the IServiceProvider.GetService(Type serviceType) interface already knows exactly what the serviceType is that it's looking for.
This gets really annoying:
IMyInterface myInterface = serviceProvider.GetService(typeof(IMyInterface)) as |
Not only is it verbose to type, but error prone when you cast the object returned by GetService.
Using generics, this is much easier and provides compile-time type safety:
IMyInterface myInterface = serviceProvider.GetService<IMyInterface>(); |
Yeah, you could define serviceProvider as an instance of MyServiceProvider:
class {
{
} } |
But that's annoying too because you have to implement MyServiceProvider and use it anywhere you are working with IServiceProvider.
It would be alot more useful if IServiceProvider already had that generic implementation. Fortuantely, C# has Extension Methods. To create the generic GetService implementation for all users of IServiceProvider in your project, extend it like this:
namespace System
{
public
static
class
GenericServiceProvider
{
[System.Diagnostics.DebuggerNonUserCode]
public
static T GetService<T>(this
IServiceProvider serviceProvider)
{
return (T)serviceProvider.GetService(typeof(T));
}
}
}Enjoy