There are a lot of articles on the web about manually modifying the list forms and the ListFormWebPart in particular, but there isn't that much information about modifying these forms programmatically, and the problems that come with that.
Customizing the ListFormWebPart
is a chapter by itself, but what we needed was to customize the EditForm.aspx. Actually, we needed to inject a control that would prevent the form to come up while the asynchronous "ItemAdded" event, triggered by a file upload to the library, was still busy retrieving metadata (also an adventure in itself, as I consider that clearly a conceptual bug in SharePoint), which would result in an exception and a failure of the upload and/or the metadata extraction.
Now, there are actually two levels of forms one could utilize: each list/library has a set of these forms (New, Display, Edit) and the content types that are associated with the list/library also have these forms.
We chose to replace the EditForm.aspx of the document-type content types with a custom aspx form with code-behind. Why code-behind? Well, there are actually a couple of things one needs to adjust on the fly to make this work. One example would be that a custom application page should reside in the "_layouts/" space and the default.master masterpage that is used by the list forms is not directly accessible from there. But the most important reason was that the ListFormWebPart requires the "ListName" (it's actually the Guid ID of the list) and the "ListItemId" (which is what it sounds like :-) to be set properly when the OnInit event fires.
So, where's the problem? The ListFormWebPart is an incredibly flexible piece of programming art that can render itself on the fly automatically, depending on what list, content type and columns are to be displayed, BUT it does not retrieve the ListName and ListItemId from the Page.REQUEST automatically. Alright, we can do that with the code-behind, but that's NOT the problem ;-) The problem is that the control isn't available during the OnPreInit event to set these properties, and before the OnInit event handler gets fired SharePoint already throws an exception stating that no item could be found for the list and itemId specified ...Duhh!
Well, the solution is actually (as most things in life) trivial: the OnInit event fires on the controls before it fires for the page. Therefore it is important to add a code-behind event handler not only at the page level but also for the Web Part itself:
And the rather simple code-behind for this looks like this:
protected void Lfwp_OnInit(object sender, EventArgs e)
string listId = Page.Request.QueryString["List"];
string itemId = Page.Request.QueryString["ID"];
ListFormWebPart lfwp = (ListFormWebPart)sender;
lfwp.ListName = listId;
lfwp.ListItemId = Convert.ToInt32(itemId);
The beauty of this solution is that the same custom EditForm.aspx can then be used not only for all Picture Libraries, but also for Document Libraries.