Question

I have a UserControl with Button inside which opens a ContextMenu when left clicked. I'm trying to pass UserControl's parent Window as a parameter to ContextMenu item's command to close that window, but with no avail. I've tried everything with RelativeSource and PlacementTarget, but parameter is always null. I'm aware that ContextMenu is not part of parent window's VisualTree. I'm currently stuck with this approach, but it is not working.

<Grid x:Name="LayoutRoot">
        <Button 
            HorizontalAlignment="Left" 
            Margin="0" 
            Style="{DynamicResource ButtonStyle1}" 
            VerticalAlignment="Top" 
            Width="120" 
            Height="25" 
            Content="Dashboard Menu" 
            TextElement.FontWeight="Bold" 
            Foreground="AliceBlue"             
            >

            <!--Tag="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={ x:Type Window}}}"-->
            <Button.ContextMenu>
                <ContextMenu DataContext="{Binding PlacementTarget, RelativeSource={RelativeSource Self}}" >
                    <MenuItem Header="Open Log Viewer" Command="{StaticResource openLogViewer}" />
                    <Separator />
                    <MenuItem Header="Exit" Command="{StaticResource exit}" CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=Window}}"/>
                </ContextMenu>
            </Button.ContextMenu>
        </Button>
    </Grid>

Command is a Referenced command defined in UserControl.Resources:

<my:CommandReference x:Key="exit" Command="{Binding Exit}" />

and it's Execute part is triggered but parameter is always null. So, my question is, what is the right way to bind parent window as CommandParameter of MenuItem. Any help is appreciated, because this thing is bothering me for almost two days.

Was it helpful?

Solution

Right way here is to not pass parent Window to the VM as CommandParameter. If this is MVVM you should be using a Messenger(MVVM Light) / EventAggregator(Prism) approach to send a Message to the Window's code-behind when the command is triggered to Close it.

Referencing Window in the VM is just plain wrong.

Just for reference, what your trying to do "can be done"

something like:

<Grid x:Name="LayoutRoot">
  <Button HorizontalAlignment="Left" 
          Margin="0" 
          Style="{DynamicResource ButtonStyle1}" 
          VerticalAlignment="Top" 
          Width="120" 
          Height="25" 
          Content="Dashboard Menu" 
          TextElement.FontWeight="Bold" 
          Foreground="AliceBlue"
          Tag="{Binding RelativeSource={RelativeSource FindAncestor,
                                                         AncestorType={x:Type Window}}}">
    <Button.ContextMenu>
      <ContextMenu>
        <MenuItem Header="Open Log Viewer" Command="{StaticResource openLogViewer}" />
        <Separator />
        <MenuItem Command="{StaticResource exit}"
                  CommandParameter="{Binding PlacementTarget.Tag,
                                             RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}"
                  Header="Exit" />
...

Update:

Download Link

When executing the "Exit" command from the ContextMenu you should see Sender Object: MvvmLight16.MainWindow in your Output Window. This output is sent from the VM.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top