[Edit #3] - to anyone reading this question: do not under any circumstance use the approach outlined in this question. It is a Coding Horr
I'll confess that I haven't dug quite as deep into your example as maybe I should, but whenever I see code-behind that's searching the visual tree, I think, could this be handled more explicitly in a view model?
It seems to me in this case that you could come up with a pretty straightforward view model - an object exposing Text
, Image
, Command
, and Children
properties, for instance - and then create a simple data template that for presenting it as a MenuItem
. Then anything that needs to alter the contents of your menus manipulates this model.
Edit:
Having looked at what you're up to in more detail, and the two examples you've linked to in your blog post, I am banging my head against the desk. Both of those developers appear to be under the misapprehension that the way to set properties on the menu items that are being generated by the template is to search through the visual tree in the ContentPresenter.Load
event after they're created. Not so. That's is what the ItemContainerStyle
is for.
If you use that, it's quite straightforward to create dynamic menus of the type you're describing. You need a MenuItemViewModel
class that has INotifyPropertyChanged
implemented and exposes these public properties:
string Text
Uri ImageSource
ICommand Command
ObservableCollection Children
Using this:
where the ItemsSource
is an ObservableCollection
, and using this template:
the menus in the window exactly represent what's in the collection, and are dynamically updated as items are added and removed, both to the top-level items and to the descendants.
There's no clambering about in the visual tree, no manual creation of objects, no code-behind (other than in the view model, and in whatever populates the collection in the first place).
I've built a pretty thoroughly worked example of this; you can download the project here.