3

I am learning wpf and mvvm and I decided to create a Soundboard for myself to practice and so far it's going pretty well. Now I have made a datatemplate where for every file that the program finds in the specified directory it will create a button with the name of the file in it and I can click it to play. So far so good. However I now tried to make a ContextMenu so that when I want to remove a file from the list I can right click and select remove, but this command doesn't work even though I have the exact same command structure for the regular button.

I am really quite confused with the whole RelativeSource thing and was already happy my regular 'play' command worked in the button.

If someone could point me in the right direction that would be great. I really could use an explanation on my specific problem as that always seems to help me more then a generic example somehow. I have tried to read on all the related questions but just don't seem to figure it out from there.

My ItemsControl:

<ItemsControl x:Name="MySounds" ItemsSource="{Binding Sounds}">

ItemTemplate:

<ItemsControl.ItemTemplate>
                <DataTemplate>
                    <StackPanel>
                        <Button Style="{StaticResource mainButton}"
                                Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemsControl}}, Path=DataContext.PlaySound}" 
                                CommandParameter="{Binding Path=Tag, RelativeSource={RelativeSource Self}}"
                                Tag="{Binding Path=Name}">
                            <TextBlock Text="{Binding Path=NormalizedName}" TextWrapping="Wrap" Height="auto" />
                            <Button.ContextMenu>
                                <ContextMenu>
                                    <MenuItem Header="{Binding Path=Name}" 
                                              Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemsControl}}, Path=DataContext.RemoveSound}" 
                                              CommandParameter="{Binding Path=Tag, RelativeSource={RelativeSource Self}}">
                                        <MenuItem.Icon>
                                            <Image Source="\WpfPractice;component\Images\CoffeeArt.png" Width="20" VerticalAlignment="Center"/>
                                        </MenuItem.Icon>
                                    </MenuItem>
                                </ContextMenu>
                            </Button.ContextMenu>
                        </Button>
                    </StackPanel>
                </DataTemplate>
            </ItemsControl.ItemTemplate>

I have a generic RelayCommand in my viewmodel and that all works, the problem really is just with the binding.

2
  • Can you try using ElementName instead of RelativeSource? Set a name to your ItemsControl (like x:Name="myIC") and then update your binding. Commented Oct 10, 2017 at 8:44
  • I tried that but it doesn't seem to work no matter what I tried. In my MenuItem header I get the same value as in my button with {binding Path=Name} but then the same command doesn't seem to work. Commented Oct 10, 2017 at 9:33

2 Answers 2

2

If you bind the Tag property of the Button to the ItemsControl, you could bind to the command using the PlacementTarget property of the ContextMenu:

<ItemsControl.ItemTemplate>
    <DataTemplate>
        <StackPanel>
            <Button Style="{StaticResource mainButton}"
                                Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemsControl}}, Path=DataContext.PlaySound}" 
                                CommandParameter="{Binding Path=Name}"
                                Tag="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemsControl}}}">
                <TextBlock Text="{Binding Path=NormalizedName}" TextWrapping="Wrap" Height="auto" />
                <Button.ContextMenu>
                    <ContextMenu>
                        <MenuItem Header="{Binding Path=Name}" 
                                  Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ContextMenu}}, Path=PlacementTarget.Tag.DataContext.RemoveSound}" 
                                  CommandParameter="{Binding Path=Name}">
                            <MenuItem.Icon>
                                <Image Source="\WpfPractice;component\Images\CoffeeArt.png" Width="20" VerticalAlignment="Center"/>
                            </MenuItem.Icon>
                        </MenuItem>
                    </ContextMenu>
                </Button.ContextMenu>
            </Button>
        </StackPanel>
    </DataTemplate>
</ItemsControl.ItemTemplate>
Sign up to request clarification or add additional context in comments.

2 Comments

Could you perhaps elaborate why and what made this work? Is it because Tag now gets set to RelativeSource ItemsControl and then the PlacementTarget is set to Tag and that in turn to DataContext? Like I stated before my understanding of RelativeSource is very bare.
The ContextMenu resides in its own visual tree so it doesn't have any ancestors. The Button has though.
0

You can try to replace your command string in your MenuItem by this :

Command="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.RemoveSound}"

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.