ToolStripMenuItem.Checked property does not set C# WinForms

89 views Asked by At

I made a music player in C# and the only problem is the playlists context menu strip when you right click on the track. When the music is in a playlist, it checks; when it is not in a playlist, it is not checked.

Note: the items are dynamically added when the user right click on the music.

My solutions:

  1. Tried to change render mode, didn't change a single thing
  2. Tried to force check the checkbox using the method but still does not work so it goes next method I tried
  3. Tried to force check only using a normal line of code
  4. Tried to change method to check the items

Here's the code:

public static void PlaylistsOpening(object sender, CancelEventArgs e, object instance, AudioFileInfo music)
{
    if (instance is Form1 form1)
    {
        if (form1.cmsPlaylists.InvokeRequired)
        {
            form1.cmsPlaylists.Invoke(new MethodInvoker(delegate { form1.cmsPlaylists.Items.Clear(); }));
        }
        else
        {
            form1.cmsPlaylists.Items.Clear();
        }

        Debug.WriteLine(sender.GetType().Name);
        IEnumerable<Playlist> playlists = Playlist.GetAllPlaylists();
        Debug.WriteLine(playlists.Count());
        foreach (Playlist playlist in playlists.ToList())
        {

            ToolStripMenuItem item = new ToolStripMenuItem
            {
                Tag = playlist,
                Text = playlist.Name
            };

            if (Playlist.GetPlaylistsWithAudioFile(music).Contains(playlist))
            {
                Debug.WriteLine("Contains");
                item.Checked = true;
            }

            item.Click += delegate
            {
                Debug.WriteLine("Clicked");
                var nItem = form1.cmsPlaylists.GetItemsFromTag(playlist)[0];
                if (nItem.CheckState == CheckState.Checked)
                {
                    Debug.WriteLine("Checked");
                    music.RemoveFromPlaylist((Playlist)nItem.Tag);
                    nItem.CheckState = CheckState.Unchecked;
                }
                else
                {
                    Debug.WriteLine("Unchecked");
                    music.AddToPlaylist((Playlist)nItem.Tag);
                    nItem.CheckState = CheckState.Checked;
                }
            };
            music.Volume = form1.SoundVolume;

            form1.cmsPlaylists.Items.Add(item);
        }
                
        if (form1.cmsPlaylists.InvokeRequired)
        {
            ToolStripMenuItem item = new ToolStripMenuItem()
            {
               Text = "Create a new playlist..."
            };

            item.Click += delegate
            {
                using (DialogPlaylist dialogPlaylist = DialogPlaylist.CreatePlaylist())
                {
                    if (dialogPlaylist.ShowDialog() == DialogResult.OK)
                    {
                        form1.cmsPlaylists.Invoke(new MethodInvoker(delegate
                        {
                            ToolStripMenuItem nItem = new ToolStripMenuItem
                            {
                                Text = dialogPlaylist.Tag.Name,
                                Tag = dialogPlaylist.Tag,
                                CheckOnClick = true,
                                Checked = true
                            };

                            nItem.Click += delegate
                            {
                                if (nItem.Checked)
                                {
                                    music.RemoveFromPlaylist((Playlist)nItem.Tag);
                                }
                                else
                                {
                                    music.AddToPlaylist((Playlist)nItem.Tag);
                                        }
                                    };

                                    form1.cmsPlaylists.Items.Add(nItem);
                                }));
                            }
                        }
                    };
                }
                else
                {
                    void AddPlaylist(object sender1, EventArgs e1)
                    {
                        using (DialogPlaylist dialogPlaylist = DialogPlaylist.CreatePlaylist())
                        {
                            if (dialogPlaylist.ShowDialog() == DialogResult.OK)
                            {
                                ToolStripMenuItem nItem = new ToolStripMenuItem()
                            {
                            Text = dialogPlaylist.Tag.Name,
                            Tag = dialogPlaylist.Tag,
                            CheckOnClick = true,
                            Checked = true
                        };

                        nItem.Click += delegate
                        {
                            if (nItem.Checked)
                            {
                                music.RemoveFromPlaylist((Playlist)nItem.Tag);
                            }
                            else
                            {
                                music.AddToPlaylist((Playlist)nItem.Tag);
                            }
                        };

                        form1.cmsPlaylists.Items.Add(nItem);
                    }
                }
            }

            ToolStripMenuItem item = new ToolStripMenuItem()
            {
                Text = "Create a new playlist..."
            };

            item.Click += (s, e2) => AddPlaylist(s, e2);

            form1.cmsPlaylists.Items.Add(item);
        }
    }
    else
    {
        return;
    }
}```

And here's how to use that method: ```
private void PlaylistsContextMenuStrip_Opening(object sender, System.ComponentModel.CancelEventArgs e)
        {
            Debug.WriteLine("Opening...");
            MusicPlayer.Events.PlaylistsOpening(sender, e, this, currentFile);
        }```
1

There are 1 answers

12
IV. On

As I understand it, you're repopulating a context menu every time a music item gets a right click and the context menu is shown. Since you're creating new ToolStripMenuItem instances anyway, consider providing all the information needed for Add/Remove operations for the music item at the time of creation. One way to do this in an efficient manner is to make a custom TSMI class:

class PlaylistToolStripItem : ToolStripMenuItem
{
    public PlaylistToolStripItem(Playlist playlist, Music music)
    {
        Playlist = playlist;
        Music = music;
        Text = playlist.Name;
        Checked = playlist.Contains(music);
        base.Click += Click;            
    }
    public Playlist Playlist { get; }
    public Music Music { get; }
    public static new event EventHandler Click;
}

Making the click event static means main form subscribes to it just once.

PlaylistToolStripItem.Click += (sender, e) =>
{
    if (sender is PlaylistToolStripItem tsmiPlus)
    {
        Debug.WriteLine($"Clicked Playlist: {tsmiPlus.Playlist.Name} Music: {tsmiPlus.Music}");
        if(tsmiPlus.Checked) tsmiPlus.Playlist.Remove(tsmiPlus.Music);
        else tsmiPlus.Playlist.Add(tsmiPlus.Music);
    }
};

Context Menu Example Code

The context menu accurately depicts the playlists that contain the right-clicked item and the add/remove behavior works as expected.

screenshot

dataGridViewMusic.CellMouseDown += (sender, e) =>
{
    if (e.Button.Equals(MouseButtons.Right) && !e.RowIndex.Equals(-1))
    {
        var menu = new ContextMenuStrip();
        var music = _allMusic[e.RowIndex];
        dataGridViewMusic.ClearSelection();
        dataGridViewMusic.Rows[e.RowIndex].Selected = true;
        foreach (Playlist playlist in _allPlaylists)
        {
            menu.Items.Add(new PlaylistToolStripItem(playlist, music));
        }
        menu.Show(new Point(MousePosition.X + 30, MousePosition.Y - 30));
    }
};