I've seen many questions on this in the forums, and no good
answer. It has even been reported as a bug, but closed. So... when
I needed the functionality myself, I took a look at the umbraco
sources and figured out what's wrong.
It may not be a bug, but it's definitely a
weird quirk. The workaround is simple though. But let's begin at
the beginning...
The Problem:
A media picker on a custom editor page doesn't show any value
when the page loads, although there is a value and it is set during
Page_Load or OnLoad. Or, in more detail:
- You write a custom section with some kind of data editor that
works against a custom database (i.e. doesn't use umbraco documents
or other objects).
- You want to let the user pick media items from umbraco and save
their id:s in your database, so that you can render them in your
usercontrol (or whatever you use to present the data in the
frontend).
- You read a HOWTO on this and pick a media picker (almost any -
most seem to work the same way), for example the mediaChooser.
- You test it, pick a media item and it works. It gets saved in
the database.
- You return to edit your data, but the media item is
GONE. It (the ID) exists in your database, but not
in your custom editor. You set it in Page_Load (as you would
normally do with control values), and you've triple-checked that.
Still doesn't work.
The Cause:
The mediaChooser (and - from what I have seen - most other media
pickers as well) handles its value in an unexpected way. More
detail:
The mediaChooser behaves like this (or actually the
BaseTreePickerEditor, which mediaChooser inherits from - and I
suspect most other media pickers do that as well):
- In OnInit, if an IData object was presented by the constructor,
its "Value" property is saved in a private variable. If IData is
null, the value will be -1.
- In OnLoad, the Value property of the control (which is defined
by a base class) is overwritten by the value in the private
variable.
- In all the following stages, the Value property is used (as it
would normally be).
This is a bit weird, as you usually create your controls in
OnInit and populate them with data in OnLoad. There are other ways
and other events that serve to make the process even more granular,
but that is the most common pattern in examples and so on. The
mediaChooser, on the other hand, assumes the data will be present
in the extractor already upon initialization.
This may be an umbraco convention (I haven't looked at the
source for other data editors), but in any case, it is unusual, and
probably quite unexpected for most people.
The Workaround:
Set the value of the media picker in OnPreRender instead (or any
other event that occurs after OnLoad but before rendering) of
OnLoad or Page_Load. If the data is only available during OnLoad,
stash it away in a private variable then, and stick it in
yourPicker.Value during OnPreRender.
Works like a charm.
Oh, and one more thing:
You don't need a value extractor (an object of a class that
implements the IData interface). Just pass null for that parameter
of the mediaChooser constructor, and use the Value property
instead. It should be "" when no media item is selected -
otherwise, it should be the media ID as a string.
Further reading:
ASP.NET Page Life Cycle Overview (a
must-read for all ASP.NET developers)
mediaChooser.cs source
BaseTreePickerEditor.cs source (inherited by
mediaChooser)
BaseTreePicker.cs source (inherited by
BaseTreePickerEditor)