A: 

I've found a way that is less of a kludge:

protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) {
    base.OnMouseLeftButtonDown(e);
    Selector.SetIsSelected(this, true);
}

For this to have any effect, the control in the ListBox' ItemTemplate needs the following XAML attribute:

Selector.IsSelected="{Binding IsSelected, Mode=OneWayToSource, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}}"

It raises two new questions:

  1. Would it be better to define my own dependency property rather than finding an attached one that isn't currently in use?
  2. Is there a way to achieve something similar in markup only?
absence
A: 

I believe the MouseLeftButtonDown is a tunnelling event: you could try using PreviewMouseLeftButtonDown, doing your processing there, then ensuring e.Handled = false; as you tried already - that should do the trick!

Hope that helps.

Kieren Johnstone
Thanks for the suggestion, but you have it backwards: MouseLeftButtonDown is the bubbling event and PreviewMouseLeftButtonDown is the tunneling one. :) How would PreviewMouseLeftButtonDown improve the situation?
absence
Preview events happen before the actual events: so if you did your processing in there, and then set e.Handled = false;, your code would get executed but the ListBox would still run its own handling code, for changing the selected item. At least hopefully; that's how I understand it!
Kieren Johnstone
A: 

Here is one simple solution, but unfortunately handler can be attached only in code, not in markup.
Event handler can be added by using handledEventsToo signature of AddHandler method:

myListBox.AddHandler(UIElement.MouseDownEvent, 
        new MouseButtonEventHandler(ListBox_MouseDown), true);

Third parameter above is handledEventsToo which ensures that this handler will be invoked no matter if it is already marked as Handled (which ListBoxItem does in ListBox).

See Marking Routed Events as Handled, and Class Handling for explanation.
See How to Attach to MouseDown Event on ListBox for example.

zendar