Thursday, May 26, 2005

Saw this in the google searches today, this one is somewhat tricky.  I haven't looked yet but I am hoping they have fixed this in .NET 2 with Template methods.

So, you have a class that you are displaying in either your own designer or at design time in Visual Studio.  One of the properties on this class is a collection that contains members of a Type you have created.  When you click the ellipses (...) button next to this property in the property grid, the designer Adds and Removes instances of System.Object in the collection, which is not very useful.  Here's how I got this to work, with examples from the very neglected TRAP project:

First, instead of something like ArrayList for the type of the property containing the collection items, I created a class that implements CollectionBase, IList, ICollection.  Take note of the class-level attributes

    [Editor("DamonPayne.Trap.UI.PersistentPropertyEditor", "System.Drawing.Design.UITypeEditor")
    ]
    public class PersistentPropertyCollection : CollectionBase, IList, ICollection    

then, these designer attributes on the property of this type:

        [Browsable(true), EditorBrowsable(EditorBrowsableState.Always),
        Editor(typeof(PersistentPropertyEditor), typeof(System.Drawing.Design.UITypeEditor) ),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
        Description("Collection of Properties that are persisted to the data store")
        ]
        public PersistentPropertyCollection PersistentProperties
        {
            get{return _persisentProperties;}
            set{_persisentProperties = value;}
        }

Now, on the type contained within my PersistentPropertyCollection (PersistentProperty), I have the following designer attributes:

    [TypeConverter(typeof(PersistentPropertyConverter)),
    EditorBrowsable(EditorBrowsableState.Always), Category("Misc"),
    ]
    public class PersistentProperty

The PersistentPropertyConverter is just a class that extends ExpandableObjectConverter and implments custom functionality.  That part is not important for this example.

The final code snippet here is the most important part.  When providing implemntations for some of the IList, etc members, I do not use the type Object but rather my own concrete type:

(...)    
    public PersistentProperty this[int index] // Indexer
        {
(...)
        public void Remove(PersistentProperty value)
        {
            _list.Remove(value);
        }

        public void Remove(object value)
        {
            _list.Remove(value);
        }
(...)
        public int Add(PersistentProperty value)
        {
            return _list.Add(value);
        }

        public int Add(object value)
        {
            if (_list.Contains(value))
            {
                return -1;
            }
            return _list.Add(value);
        }

        public void AddRange(PersistentProperty[] items)
        {
            foreach(PersistentProperty p in items)
            {
                Add(p);
            }
        }
(...)

Notice that for some of these the methods are overloaded for type Object and my concrete type.  The designer is able to figure it out, and voila, my custom collection editor for the TRAP gui looks like so:

I'll have to post more on .NET designer stuff when I get the chance.

Thursday, May 26, 2005 3:36:49 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [5]  |  Trackback

I'm not sure if I've mentioned before how much I love delegates, but I do.  I made a new friend today in the form of System.Predicate<T>, another powerful aspect of the generics support in .NET 2.

A Predicate is a delegate wraps a method that accepts an instance of the Teplate type and returns whether or not the specific instance matches whatever condition the predicate represents.  Many of the framework classes in .NET 2 work with the Predicate<T> generic.  One example might be a generic List<T>,

(...)
public World(Device dev)
{
_device = dev;
WorldEntities = new List<Entity>(100);
_removePredicate = new Predicate<Entity>(ShouldRemove);
}
(...)
public List<Entity> WorldEntities;
private Device _device;
private Predicate<Entity> _removePredicate;
(...)
protected void RemoveDisposed()
{
WorldEntities.RemoveAll(_removePredicate);
}

protected bool ShouldRemove(Entity target)
{
return target.IsDisposed;
}
(...)

That is the first use I came across, but obviously there are many other saucy uses for this.  Obviously you could do something almost this good in .NET 1, but the strong typing of the parameter class is what makes it cool.

Thursday, May 26, 2005 2:56:13 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback

Before Beta 2 came out I had been reading that SQL Mobile databases and the System.Data.SqlServerCe namespace would work from the full .NET 2 framework.  Once I actually tried this I could find very little conversation on the subject, except for here.  I tried exactly what this author had done and I was getting all kinds of assembly loading errors. I was finally able to access a .sdf database from my winforms app, but I'm not happy with the solution.

Beta 2 installs several System.Data.SqlServerCe .Dll files.  The one that will actually load from a desktop winforms application is in C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\, with a description of "Microsoft SQL Mobile" and version 9.0.242.0.  When I tried this at first, I was still getting errors thrown out of this assembly with descriptions like "sqlcese.sys.dll".  In the same IDE directory mentioned above there are several .DLL files with similar names.  I was ultimately able to get my SqlCe connection to work by copying some of these to my application's bin\Debug directory:

  • sqlceca30.dll
  • sqlcecompact30.dll
  • sqlceer30en.dll
  • sqlceme30.dll
  • sqlceoledb30.dll
  • sqlceqp30.dll
  • sqlcese30.dll

This is the part I'm not happy with.  The fact that the .DLL that works is in a visual studio directory and apparently needs some other DLLs from the same to run probably means one of two things.  Either my Beta 2 installation is slightly funky, or Sql Mobile from Full framework is not going to be something you can do on a computer without Visual Studio installed.  I hope the latter is not the case.  It would be very nice to be able to use Sql Mobile instead of access, and also to be able to use the power of a desktop PC to build .SDF databases.  I have not messed with the bulk copy functionality in Sql Server 2005 yet, so perhaps that is easy to automate.  Again though, this implies you should be able to use a .SDF datbase from desktop code.

Thursday, May 26, 2005 9:00:14 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [2]  |  Trackback
 Wednesday, May 25, 2005

Today's By Request items, taken from the google search records.

log4net from ASP.Net

There have been some searches talking about how to configure log4net to work within your ASP.NET application.  I admit its not as straightforward as it should be.  There are 3 things to remember:

  1. Whatever user your ASP.NET application runs as needs permissions to whatever resources you are trying to access.  For log files this includes create/modify perms in the directory you want to log to.
  2. You need to add a log4net config section handler and config section to your web.config file:

<configSections>
<section name="log4net"
type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
    <log4net>
        <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
            <param name="File" value="C:\\Projects\\TheShaft\\MobileServerEndpoint\\ShaftLog.txt" />
            <param name="AppendToFile" value="true" />
            <param name="RollingStyle" value="Date" />
            <param name="MaxSizeRollBackups" value="10" />
            <param name="StaticLogFileName" value="true" />
            <layout type="log4net.Layout.PatternLayout">
                <param name="ConversionPattern" value="%d [%t] %-5p %c [%x] - %m%n" />
            </layout>
        </appender>
        <root>
                <level value="DEBUG" />
                <appender-ref ref="RollingFileAppender" />
        </root>
    </log4net>

  3. In the Application_Start event of your Global, you need to tell log4net to configure itself:

        protected void Application_Start(Object sender, EventArgs e)
        {
            log4net.Config.DOMConfigurator.Configure();
            ILog log = LogManager.GetLogger( GetType() );
            log.Info("Application_Start");
        }

And...

Compact Framework 2 on CE.Net

Right now, in Beta 2, you can run CF2 applications on WindowsMobile 2003, CE.NEt 4.0 and up, and WindowsMobile Smartphone.  If you start a SmartDevice CAB project, you will see the "MinVersion" parameter equal to 4.0.  However, I have been told directly from a Microsoft employee (via the newsgroups) that this will not be the case when Visual Studio 2005 goes final.  For the CE.NET OS, only version 5 will run Compact Framework 2 applications.

 

Wednesday, May 25, 2005 8:14:03 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback

As many of you nerds know, DasBlog has a feature whereby it will record search strings used by search engines to reach your site.  Its become part of my daily entertainment to look at this list and click back to the referring searches.  Some of the items are scary or ridiculous like "Damon payne milwaukee salary last year" but a lot of them are related to content I've posted, which is cool.

A lot of the search items are looking for questions I did not answer but could answer easily.  I may make this part of my daily routine to post an answer to something that was the topic of someone's search but not already on my site.  A lot of these are compact framework/smartphone questions but some other interesting things as well.

Wednesday, May 25, 2005 7:56:43 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, May 24, 2005

OK, so, I've had a chance to mess with Direct 3D more.  As soon as you figure out basically how to draw 1 thing on the screen and you want to experiment, its best to create some kind of framework.  It would be nice to draw a scene, isolate your experiment to one class, and make it easy to add/remove/alter a particular aspect of the scene you are drawing.  A dynamic scene could be rendered given the following metaphors:

An Entity class that represents any draw-able item.  The Entity is responsible for loading its vertices, points, textures, etc.  A non-staic light source could also be an entity in which case the Entity would load its color information etc.  The Entity could be an abstract base class.  Entities are added to a World which represents all the dynamic items that could be rendered.  While Entities might not be visible at all times (View Coordinates, World Coordinates, Painter's Algorithm discussions in future posts) they might be thinking/acting elsewhere so they need periodic chances to do something even if they are not visible.  A simple DirectX program/Render loop might go like this:

  1. Initialize Device and drawing surface properties
  2. Create a World
  3. Create some Entity objects to go in the world
    1. Entity objects load their Model (vertices, colors, textures, etc) information
    2. Entities are given a reference to the Device so that they can Render themselves later.
  4. While your World is running
    1. Given each item a chance to update itself
    2. Process user input if applicable
    3. Begin a scene
    4. Tell each item to Render itself
    5. Do lights/effects passes etc
    6. End Scene
    7. Present Scene
    8. Repeat

All in all, the render loop for a simple game/simulation might be pretty simple.  The internet could use a lot more sample code for Direct3D, at least I've been unable to find much on how various things are typically done.  For example, when an Entity changes position in the World is it customary to rebuild it or to Transform its vertices to reflect the new position?  From what I can see, Transformations are used to model the observer changing its view position from one place to another, yet, rebuilding a vertex list seems very inefficient.  Consider this partial snippet for drawing a triangle with 3 vertices and some color:

...
class MovingTriangle : Entity
{
private CustomVertex.TransformedColored[] _verts;
private VertexBuffer _vertBuffer;
private float _topX;

...

public override void Render(Microsoft.DirectX.Direct3D.Device dev)
{
dev.SetStreamSource(0, _vertBuffer, 0);
dev.VertexFormat = CustomVertex.TransformedColored.Format;
dev.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
}

public override void DeviceAquire()
{
_vertBuffer = new VertexBuffer(typeof(CustomVertex.TransformedColored), 3, _dev, 0, CustomVertex.TransformedColored.Format, Pool.Default);
_vertBuffer.Created += new EventHandler(_vertBuffer_Created);
_vertBuffer_Created(null, EventArgs.Empty);
}

void _vertBuffer_Created(object sender, EventArgs e)
{
DoCreateBuffer();
}

private void DoCreateBuffer()
{
GraphicsStream stream = _vertBuffer.Lock(0, 0, 0);
_verts = new CustomVertex.TransformedColored[3];

_verts[0].X = _topX;
_verts[0].Y = 50;
_verts[0].Z = -0;
_verts[0].Rhw = 1;
_verts[0].Color = System.Drawing.Color.Red.ToArgb();
//
_verts[1].X = _topX + 100;
_verts[1].Y = 250;
_verts[1].Z = -0;
_verts[1].Rhw = 1;
_verts[1].Color = System.Drawing.Color.Red.ToArgb();
//
_verts[2].X = _topX - 100;
_verts[2].Y = 250;
_verts[2].Z = -0;
_verts[2].Rhw = 1;
_verts[2].Color = System.Drawing.Color.Red.ToArgb();

stream.Write(_verts);
_vertBuffer.Unlock();
}
}
...

It seems as though vertex recreation would be horribly inefficient.  I just ordered a pile of DirectX books from my favorite online store to shed some light on common D3D practices.  As soon as I get through the next chapter in my Physics book I can share the nature of my ridiculous DirectX test project.

 

Tuesday, May 24, 2005 9:58:40 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [5]  |  Trackback
 Monday, May 23, 2005

 After passing it at B&N several times I picked this book up yesterday.  I really enjoyed my Physics in college but of course being in a hurry to graduate left no time for pursuing any interesting things.  I do regret that my physics class was not Calculus based.  When I did take Calculus the physics applications were by far the most interesting parts.  When we were shown that the first derrivative of the acceleration function is the distance function I was blown away as it was the first time I'd ever seen a mathematical idea (derrivatives) explain not a phenomenon in reality (If the train is going 100 km/h and the city is 50 km away...) but an actual aspect of reality.

Back to the book, I just started reading the first few chapters: a refresher on basic physics.  More impressions as I read through it but you can probably expect to see a DamonPayne.Physics C# library posted here. 

When picking this book up I also realized how utterly ludicrous it is that the English measurement system is still in use.  Over the course of the year, I'm going to try to convert to thinking of things in terms of Kilometers to my house and my car's 0-100km acceleration time.

Monday, May 23, 2005 8:06:15 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Friday, May 20, 2005

I have always kept it technology related here, since I have a personal site for anyone who might care to read about my opinions on life in general.  There's something going on right now is worthy of a cross-post, and a lot more than that too: Social Security reform. Our President visited our state this week to talk about Social Security reform.  He's been taking a lot of heat for this, and of course it is political suicide (or heroism?) , which is why its an issue to look at when you are not up for re-election.

My personal philisophy is largely objectivist which puts me at odds with at least half the population right off the bat.  There is one principal that I would think anyone can identify with (even if only in their most hidden thoughts) and that is self interest.  Social Security hurts almost everyone, from the lowest wage earner to the wealthiest industrialist.  I say almost everyone because there is some value in taking care of those who are unable to work.

I've always known Social Security would not be enought to live on after retirement, but when I started getting statements from the govermnment as to what I could expect, it was still shocking.  My monthly check from Uncle Sam will likely not be enough to pay the cable bill in terms of 2040 dollars.  Yet we pay roughly 7.5% (with medicare, etc) payroll tax on the first $90,000 we make.  Our employer matches this, so lets use 15% as a nice round number for argument's sake.  Let's say I make $20,000 per year, and I work for 40 years.  Using this calculator from the SSA I can expect a yearly payout of ~ $9,400.  Ouch!  By compairson:

  • My and my employer's payroll taxes over that working career could be invested at Zero percent interest, in my mattress, to get a payout of $6,000 per year.
  • In a no-risk 5% money market, my money alone (not counting my employer's payroll tax) would come out to be about $9,500 per year.
  • A conservative money market at an average 7% rate of return for just my payroll tax would give me $16,400 per year.
  • Now let's get crazy: if my mutual fund return averaged 7.5% and I was able to invest both my payroll tax and my employer's payroll tax, my nest egg could pay me $37,700 per year.

I am assuming 20 years of retirement payout here.  I also ran the numbers (in Excel and the Social Security Administration web site) for a $90,000 salary.  The fact of the matter is, unless you are one of the few who are disabled and cannot work, Social Security is a ripoff.  I am not advocating leaving those people high and dry either, so settle down. 

Now, in addition to you getting a terrible rate of return on the 15% of your salary that goes to SS, consider that there are also quite a few popular ways to save additional money for retirement.  401k, company pensions, Roth IRA, etc. 

What is my point?  My point is that in terms of the total cost of employing you and your salary, you and others on your behalf are probably spending a grand total of 23% or more of that salary on your retirement; to retire with a similar standard of living you probably only need 7.5% of that money. 

A lot of other things could be done with a lot of money that is going into a large, inefficient system that is periodically raided by Congress.  My vote is give it back to people to spend.  Social Security reform is good.

Friday, May 20, 2005 9:20:05 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, May 18, 2005

I have never done DirextX programming before, as I mentioned my graphics experience is in 2D software drawing APIs (ie, line/pixel/arc drawing) and OpenGL.  Tonight I got some paying work done and needed to dabble in something so I got the latest and greatest Managed DirectX download from MSDN, dated April 2005.  I have mostly been messing around with the sample programs tonight, and just started combining some of the samples to do something more than hello, world.  "Hello World" in graphics land is drawing a shaded triangle, by the way.

A few observations from an hour of messing around:

The Good

Things have come a long way since I last did anything with graphics.  Creating a drawing device can be done in as little as 2-4 lines of code.  Its fairly easy to get to the point where you can start messing around and see something on the screen.  Microsoft has also included some Intellisense documentation, which was missing when I played with DirectShow a while back.

                PresentParameters presentParams = new PresentParameters();
                presentParams.Windowed=true;
                presentParams.SwapEffect = SwapEffect.Discard;
                _device = new Device(0, DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, presentParams);

... then draw away.

The Bad

Performance from Managed code does not look like its going to be pretty.  I'm thinking it should be able to draw the simple scene shown above more than 42 times per second.  Also, many of the examples included in this release of the SDK do not compile or work.  The most annoying thing I encountered is the code included for drawing text to the Direct3D device did not compile.  It looks like MSFT has been tweaking the managed API and has not updated all the samples.  For what its worth, I got the "GraphicsFont" to work with minor code changes, and I'm including the file here for download on the off chance anyone else is having issues. 

GraphicsFont.cs.rename (22.61 KB)

More observations as I get time to make them.

Wednesday, May 18, 2005 9:32:50 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [5]  |  Trackback
Old Content Archives
Wednesday, May 18, 2005 1:14:35 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [5]  |  Trackback
 Tuesday, May 17, 2005
New DasBlog site up, with a personal note: why did I become a programmer?
Tuesday, May 17, 2005 2:49:08 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [3]  |  Trackback