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
    This might have the answer to your problem: https://stackoverflow.com/questions/15033522/wpf-contextmenu-woes-how-do-i-set-the-datacontext-of-the-contextmenu – o_weisman Jul 17 '18 at 06:14

1 Answers1

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}
Rekshino
  • 6,954
  • 2
  • 19
  • 44