-1

I have a small but annoying problem with my ContextMenu in a WPF application.
I use a DataTemplate for my List of ViewModel-objects to create the visual elements. In the DataTemplate I simply set my UserControl like this:

<!-- Define a data-template for the 'RoomViewModel' class. This generates the UI for each node. -->
<DataTemplate DataType="{x:Type model:RoomViewModel}">
    <network:RoomView network:ConstraintView.ArgumentChanged="ConstraintView_ArgumentChanged"></network:RoomView>
</DataTemplate>

I want the RoomView to have a ContextMenu where a RelayCommand should be executed if the user clicks on the MenuItem. My UserControl for the RoomView looks like this at the moment:

<UserControl x:Name="userControl" x:Class="NetworkUI.RoomView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:network="clr-namespace:NetworkUI"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300" DataContextChanged="userControl_DataContextChanged">
    <UserControl.Resources>
        <!-- UI commands -->
        <RoutedCommand x:Key="Commands.NewConstraintCmd"></RoutedCommand>
    </UserControl.Resources>
    <UserControl.CommandBindings>
        <CommandBinding x:Name="newConst" Command="{StaticResource Commands.NewConstraintCmd}" Executed="NewConstraint_Executed"></CommandBinding>
    </UserControl.CommandBindings>
    <Grid Width="Auto" Height="Auto" MinWidth="50" >
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
        </Grid.RowDefinitions>
        <Grid Grid.Row="0" Width="Auto" Height="20" MinWidth="50" >
            <Rectangle Stroke="Black" Fill="White" RadiusX="4" RadiusY="4" SnapsToDevicePixels="True" ></Rectangle>
            <Grid Margin="-4" >
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="*" MinWidth="10" />
                    <ColumnDefinition Width="Auto" />
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="*" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>
                <network:EditableTextBlock Grid.Column="1" Grid.Row="1" x:Name="nameTextBox" Text="{Binding Name, Mode=TwoWay}" HorizontalAlignment="Center" VerticalAlignment="Center" BorderBrush="{x:Null}" />
                <network:ConnectorItem Grid.Row="1" Grid.Column="0" DataContext="{Binding Connectors[0]}" />
                <network:ConnectorItem Grid.Row="1" Grid.Column="2" DataContext="{Binding Connectors[1]}" />
            </Grid>
        </Grid>
        <StackPanel Grid.Row="1" x:Name="roomProperties" Width="Auto" HorizontalAlignment="Stretch" >
            <ItemsControl ItemsSource="{Binding PropertyGroups}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <network:ConstraintCollectionView></network:ConstraintCollectionView>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </StackPanel>
    </Grid>
    <UserControl.ContextMenu>
        <ContextMenu x:Name="contextMenu">
            <MenuItem Header="new Constraint" Command="{StaticResource Commands.NewConstraintCmd}"></MenuItem>
        </ContextMenu>
    </UserControl.ContextMenu>
</UserControl>

I am not really sure if my UserControl code is ok. In my CodeBehind file I define a

public ICommand NewConstraintCmd;

-Command that should be executed when the user clicks the Item. My Executed handler is simple and looks like this:

private void NewConstraint_Executed(object sender, ExecutedRoutedEventArgs e) {
    ViewModel.AddConstraint();
}

The ViewModel is indeed a RoomViewModel and the NewConstraintCmd is set in the DataContextChanged - event (not displayed here).

My simple question is, why is my ContextMenu-Item always disabled? I mean the RelayCommand.CanExecute is never checked, is this the problem maybe?

I didn't find any solution for my problem yet.
Thank you for any help!

Eru Iluvatar
  • 353
  • 1
  • 5
  • 17
  • Well I tried something different now: When I just set the Command directly to my 'NewConstraintCmd' in the XAML file, I see the MenuItem enabled. I dont't really need my RoutedCommand and my CommandBinding in that case. I just wanted to know if this approach is ok? The problem with this 'solution' is, that the Command is not executed (why? :( ). I also experimented using no command at all and it works just fine if I only use a click-event-handler. I still want to be able to use a command to maybe add a shortcut later. Maybe it's just a little problem, but I don't get it at the moment :) – Eru Iluvatar Aug 15 '14 at 14:54
  • With your first approach if you explicitly first left click on UserControl and then open the context menu, does it show enabled menu item? – Rohit Vats Aug 15 '14 at 14:57
  • 1
    Also, you can try the approach defined [here](http://stackoverflow.com/a/601415/632337). – Rohit Vats Aug 15 '14 at 14:59
  • Thank you, I posted the answer based on that link! – Eru Iluvatar Aug 15 '14 at 15:47

1 Answers1

-1

Thank you Rohit Vats! I changed my ICommand definition to this:

public static readonly ICommand NewConstraint = new RelayCommand((rvm) => AddConstraint(rvm));

Since this is a static method I needed the parameter (the DataContext of my RoomView).
My Method is defined like this now:

private static void AddConstraint(object rvm) {
    if (rvm is RoomViewModel)
        (rvm as RoomViewModel).AddConstraint();
}

So first the parameter is checked and if it is ok (a RoomViewModel object) I call the actual function on the object.

I have no idea why it works now, really :/.

My XAML code for the MenuItem now looks like this:

<MenuItem Header="new Constraint" Command="network:RoomView.NewConstraint" CommandParameter="{Binding}"></MenuItem>

As mentioned before I need the CommandParameter to call a function on it. Since the needed Object is my DataContext I just use the {Binding} to pass the object.

This really works fine now, I hope it will work with InputBindings as well in the future :)! Thank you again for the help!

Eru Iluvatar
  • 353
  • 1
  • 5
  • 17