Newbie: How to add a dynamic ContextMenu using Caliburn

Topics: Getting Started
May 6, 2013 at 4:38 PM
Edited May 6, 2013 at 5:15 PM
Hi,

I am new to caliburn, therefore this might be a stupid question. I have a ListView and want to add a ContextMenu, but the Header-text for the ContextMenu should contain information from the Item the ContextMenu should be opened at.
E.g.:
A List with int's and when I right-click on an int, I want the ContextMenu-Item-Header to be something like "Open {0} with ..." where {0} should be replaced with the selected ListViewItem.
Is that possible using caliburn micro?

My first try is something like this - seems to work but is this "the way to go"?
<Window x:Class="CaliburnTest.AppView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:cal="clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro"
        Title="AppView" Height="300" Width="300">
    <Grid>
        <ListView x:Name="List" SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
                  cal:Message.Attach="[Event ContextMenuOpening] = [Action ContextMenuOpening($source)]">
            <ListView.ContextMenu>
                <ContextMenu>
                    <MenuItem Header="{Binding OpenMenuItem}" cal:Message.Attach="Open($view)"></MenuItem>
                </ContextMenu>
            </ListView.ContextMenu>
        </ListView>
    </Grid>
</Window>
public class AppViewModel : PropertyChangedBase
    {

        public AppViewModel()
        {
            this._list = new BindableCollection<int>();
            Random rand = new Random();
            for( int i = 0; i < 100; i++ )
            {
                this._list.Add( rand.Next(100) );
            }
        }

        private IObservableCollection<int> _list;

        public IObservableCollection<int> List
        {
            get { return _list; }
            set
            {
                _list = value;
                NotifyOfPropertyChange( () => List );
            }
        }

        private int selectedItem;

        public int SelectedItem
        {
            get { return selectedItem; }
            set 
            { 
                selectedItem = value;
                NotifyOfPropertyChange( () => SelectedItem );
            }
        }

        public void ContextMenuOpening( object dataContext )
        {
            this.OpenMenuItem = string.Format( "open {0} ... ", selectedItem );
        }

        private string _openMenuItem;

        public string OpenMenuItem
        {
            get { return _openMenuItem; }
            set
            {
                _openMenuItem = value;
                NotifyOfPropertyChange( () => OpenMenuItem );
            }
        }
    }
May 12, 2013 at 11:40 AM
Hi zpete,

That looks fine. Perhaps an improvement would be to break the context menu bits out into a reusable ContextMenuViewModel which you could then bind to a data templated ContextMenu object. Either way it looks ok.