1

I can't seem to get the binding to a command from my view model to work. The parent of the context menu which is a listmenu binds its itemssource to a property in the UserControl called ActiveArtists. As so I tried to bind "back" to the original ViewModel; of which is a child of another ViewModel; with RelativeSource. However the way I did it doesn't seem to work.

XAML for the tabitem

<TabItem DataContext="{Binding Children[1]}" Header="Database"> <Grid Background="#FFE5E5E5" IsEnabled="True"> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <ListView x:Name="ArtistListView" ItemsSource="{Binding ActiveArtists}" SelectedItem="{Binding SelectedArtist}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" Margin="10,10,5,10"> <ListView.ContextMenu> <ContextMenu FontSize="10"> <MenuItem Header="Delete Artist" Command="{Binding Path=DeleteArtistCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabItem}}}" /> </ContextMenu> </ListView.ContextMenu> <ListView.View> <GridView> <GridViewColumn Header="Artist" DisplayMemberBinding="{Binding Name}" Width="150"/> </GridView> </ListView.View> </ListView> <ListView x:Name="listView1" ItemsSource="{Binding ActiveAlbums}" SelectedItem="{Binding SelectedAlbum}" Margin="5,10,5,10" Grid.Column="1"> <ListView.View> <GridView> <GridViewColumn Header="Album" DisplayMemberBinding="{Binding Name}" Width="150"/> </GridView> </ListView.View> </ListView> <ListView x:Name="listView2" ItemsSource="{Binding ActiveTracks}" SelectedItem="{Binding SelectedTrack}" Margin="5,10,10,10" Grid.Column="2"> <ListView.View> <GridView> <GridViewColumn Header="Track" DisplayMemberBinding="{Binding Name}" Width="150"/> </GridView> </ListView.View> </ListView> 

Code for the MainWindowViewModel

public class MainWindowViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private void RaisePropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } private MusicLogClient _musicLog; ObservableCollection<object> _children; public ObservableCollection<object> Children { get { return _children; } } public MainWindowViewModel() { string rootPath = "C:\\Programs\\MusicLog\\UserData\\"; _musicLog = new MusicLogClient(new UserSettings(rootPath+"database.xml", rootPath+"credentials.xml")); _children = new ObservableCollection<object>(); _children.Add(new ArtistEntryViewModel(_musicLog)); _children.Add(new DatabaseViewModel(_musicLog)); } 

Update:

I tried implementing one of the solutions proposed but it still doesn't link to the command.

This is the updated code snippet.

<ListView.ContextMenu> <ContextMenu FontSize="10" DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}"> <MenuItem Header="Delete Artist" Command="{Binding DeleteArtistCommand}" /> </ContextMenu> </ListView.ContextMenu> 

Update 2:

ViewModel used -

public class DatabaseViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private void RaisePropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } private MusicLogClient _musicLog; public ICommand DeleteArtistCommand; private ObservableCollection<Artist> _activeArtists; public ObservableCollection<Artist> ActiveArtists { get { return _activeArtists; } set { _activeArtists = value; RaisePropertyChanged("DatabaseArtists"); } } private Artist _selectedArtist; public Artist SelectedArtist { get { return _selectedArtist; } set { _selectedArtist = value; RaisePropertyChanged("SelectedArtist"); GetDatabaseAlbums(); ActiveTracks = null; } } private ObservableCollection<Album> _activeAlbums; public ObservableCollection<Album> ActiveAlbums { get { return _activeAlbums; } set { _activeAlbums = value; RaisePropertyChanged("ActiveAlbums"); } } private Album _selectedAlbum; public Album SelectedAlbum { get { return _selectedAlbum; } set { _selectedAlbum = value; RaisePropertyChanged("SelectedAlbum"); GetDatabaseTracks(); } } private ObservableCollection<Track> _activeTracks; public ObservableCollection<Track> ActiveTracks { get { return _activeTracks; } set { _activeTracks = value; RaisePropertyChanged("ActiveTracks"); } } private Track _selectedTrack; public Track SelectedTrack { get { return _selectedTrack; } set { _selectedTrack = value; RaisePropertyChanged("SelectedTrack"); } } public DatabaseViewModel(MusicLogClient musicLog) { _musicLog = musicLog; GetDatabaseArtists(); LoadCommands(); } private void GetDatabaseArtists() { ActiveArtists = _musicLog.GetArtists().ToObservableCollection(); } private void GetDatabaseAlbums() { if (SelectedArtist != null) { ActiveAlbums = _musicLog.GetAlbums(SelectedArtist).ToObservableCollection(); } } private void GetDatabaseTracks() { if (SelectedAlbum != null) { ActiveTracks = _musicLog.GetTracks(SelectedAlbum).ToObservableCollection(); } } private void LoadCommands() { DeleteArtistCommand = new CustomCommand(DeleteArtist, CanDeleteArtist); } private void DeleteArtist(object obj) { _musicLog.RemoveArtist(SelectedArtist); } private bool CanDeleteArtist(object obj) { if (SelectedArtist != null) { return true; } return false; } } 
1

1 Answer 1

3

Just set DataContext for your ContextMenu:

<ContextMenu FontSize="10" DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}"> 

Update:
DeleteArtistCommand must be a property, not a field.

public ICommand DeleteArtistCommand {get;set} 
Sign up to request clarification or add additional context in comments.

4 Comments

Hi, I tried to implement your solution but it doesn't seem like it fixes the problem.
Is your DeleteArtistCommand in the same class where ActiveAlbums is?
Yes it is, I'll put up the entire DatabaseViewModel
Oh shoot, totally missed that. Thanks for the help!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.