Click here to Skip to main content
15,888,521 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
See more:
I have created a class called Songs. It contains some variables called: "name","fullname" and "directory".

The idea on the Form is for a user to use OpenFileDialog to select a .wav file to add the song to a list in the a listbox. Everytime the user enters a file, it should create a new Songs (the class) thing.
So the song they input will have 3 informations attached because it's a class Songs (Sorry If I'm not making sense, correct me if I'm wrong!).

Each item on the list will have:
name - The name shown on the list extracted from the FileName e.g. song.wav
fullname - The full name including directory e.g. C:\Users\Joel\Music\song.wav
directory - Just the file name directory e.g. C:\Users\Joel\Music

Ok, how do I do this?

I have the class set up but I don't know how to create a new version of the Songs class for each item input to the list for each song!
The user will see the listBox like a list of the "name" property for each one without the directory attached.
like song1.wav song2.wav song3.wav ...
but when they double click it I want the program to read the directory to find the file.
So when you double click the song on the listbox it will read the property "fullname" to find the file.

The problem i have is:
I have used classes before but I always had to declare the class thing before at the start of the program like "Static Monster example" (Monster is class name)
but I always had to declare these at the start. But for this new program I can't do that because I need it to create a new one for each song the user chooses.

Any ideas?
I'm sorry for such a crap post and badly explained things and you might not understand any of it at all. But I really need help with this - I'll rephrase if you want, thanks
Posted
Comments
R. Giskard Reventlov 27-Jan-12 20:04pm    
Smells suspiciously like homework.
Joel Whatley- 27-Jan-12 20:15pm    
Lol no =) I am far infront of my group in college, I get bored because the other stuff is too easy, and I am just searching Windows just trying to re-create simple applications in a basic way. So far I have done a calculator, word processor and now a music player (this post) im doing. : )
LanFanNinja 27-Jan-12 20:42pm    
Check solutions below.
LanFanNinja 27-Jan-12 22:22pm    
If you are reading this comment after checking my solution please recheck it as there was a mistake I fixed.

changed
Song selectedSong = songs[listBox1.SelectedValue];
to
Song selectedSong = songs[listBox1.SelectedItem.ToString()];
BillWoodruff 27-Jan-12 23:19pm    
LanFanNinja's solution below (note his revision in a later comment) is a fine example for you to study.

The simplest way, I think to "get a grip" on what you are struggling with here is to think of a Class (that is not "static") as being a special type of Object which is a template for the making of Instances of the Object-template. It's a "blue-print:" a "specification," an "abstraction."

And, there's nothing wrong with having as many properties, or fields, as you like in your Object definition, and calculating them and setting them (for those fields which need to be calculated) in the Constructor of the Object !

If those fields (calculated) are, in the future, frequently accessed: it makes sense to calculate them once, in the Constructor.

You can define your entire Class as Public if you wish.

What you define as Public within the class (fields, properties, methods, even other Classes, or structs), should be, imho, choices made based on future needs to "expose" those "class members" outside the Class to instantiators/consumers of the Class (possibly even "inheritors from" the Class).

And, the need, at times, to expose different internal parts of a Class, to different "consumers" or "inheritors," can be handled by the skilfull use of Interfaces, but that's an advanced topic, and, I think, not relevant here.

Joel,

I feel you have a mess about types and objects (instances), and references. The class Song would be a type and not an object.the It should not be plural, according to the naming conventions. The class under this name is only one, but many instances can be created. You don't create "a new Songs (a class) thing". An example if the instance is song in the code by LanFanNinja. Now, this is a variable name, which is actually the reference to the actual object, and the type is the reference type. It means that if you did
C#
Song song1 = new Song("first");
Song song2 = song1;
you would have two references referencing only one object created using the constructor.

If you copied, say, integer object in its natural (not boxed) form, you would have two different objects. If you change one of them, another one would remain the same. With reference objects, if you changed song2 you would observe this change in song1 as well, because song2 and song1 work like the same object; you consider these two variables as the names of the same thing.

—SA
 
Share this answer
 
Comments
LanFanNinja 27-Jan-12 22:45pm    
+5 Correct. This certainly needed to be pointed out.
Sergey Alexandrovich Kryukov 27-Jan-12 22:49pm    
Thank you very much.
--SA
BillWoodruff 27-Jan-12 23:10pm    
The class "Song" is both a Type, and Object: specifically "Song" is a Type of user-defined class, a sub-type of reference Types.

MSDN: "All types derive from the System.Object base type." http://msdn.microsoft.com/en-us/library/2hf02550(VS.71).aspx

Instances of the class "Song" are, of course, Objects.
Sergey Alexandrovich Kryukov 28-Jan-12 0:40am    
Wrong. Song is Object, of course, but Object is not an object (not an instance), but a type. Isn't that obvious?
So, Song is System.Object but not an object (not an instance).
Is is clear now?

Now, in Delphi, a major predecessor of .NET and C#, one can work with a class as an object, that is, a class is a first-class object called "meta-class". .NET is less advanced. The role of meta-class is modeled by the instances of the class System.Type, but this type is only one for all types, which is less powerful than meta-classes.

--SA
BillWoodruff 28-Jan-12 5:05am    
Wrong. You have simply further obfuscated a very simple fact about .NET. Read the MSDN documents referred to above.

What you are doing is confusing the fact that on the macro-level Classes in .NET are Types, in fact, technically "first-class Types," in terms of "formal Computer Science; however, on the micro-level, in C# code: Classes themselves cannot be arguments to such methods as GetType(), etc.

From the C# "ground-level" perspective it does not make sense to consider the actual Type of a Class, even though a Class is a Type, of a special "flavor," as I mentioned: a sub-type of Reference Types, which a sub-type called a "User defined Class."

The equivalency of any instance of a Class to both 'Object and 'System.Object is a reflection of an inheritance relationship.

// assume an instance of Song has been instantiated
// named 'instanceOfSong
Console.WriteLine(instanceOfSong is Object);
Console.WriteLine(instanceOfSong is System.Object);
Console.WriteLine(instanceOfSong is Type);
Console.WriteLine(instanceOfSong is System.Type);

The output of these three statements will be:

True
True
False
False

Of course, calling instanceOfSong.GetType() will return, as expected: "Song."

Also, go into .NET, and type System.Type somewhere and observe what IntelliSense tells you in the pop-up.

A further experiment that may open your eyes: set a breakpoint at a place where you have access to some Public Class you have created: open the Visual Studio "Command Window" and try these:

? Song

? typeof(Song)

Then contrast the output of the 'typeof result above with:

? Type.GetType("Song")

Which will be "null."

Bringing in Delphi here is a "red-herring:" a distraction that has nothing to do with the topic at hand.

Hopefully, between the two of us, we have now completely befuddled the original poster :)
Here is my latest solution for you hopefully it is more what you are looking for.

The songsListBox holds the songs you add using the addSongsButton theses songs can then be selected and sent to the playListBox using the addToPlaylistButton.

I am sure you can figure out the rest of the changes but if not just ask and I will help you.

NOTE: Again this code was not heavily tested so if you encounter any strange problems let me know and myself or someone else on here will try to help you.

Let me know how it works out for you. :)

C#
public partial class Form1 : Form
{
    SoundPlayer player;
    Dictionary<string, Song> songs;
    Song selectedSong = null;

    public Form1()
    {
        InitializeComponent();

        songs = new Dictionary<string, Song>();

        // this allows you to select multiple songs from the 
        // songsListBox to add to the playListBox by holding
        // down the Ctrl or Shift key.
        songsListBox.SelectionMode = SelectionMode.MultiExtended;

        //allows multiple files to be selected
        // by holding down the Ctrl or Shift key.
        openSongDialog.Multiselect = true;
    }

    //add songs to the songsListBox
    private void addSongsButton_Click(object sender, EventArgs e)
    {
        if (openSongDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
        {
            for (int i = 0; i < openSongDialog.FileNames.Length; i++)
            {
                Song song = new Song(openSongDialog.FileNames[i]);
                songs.Add(song.Name, song);
                songsListBox.Items.Add(song.Name);
            }
        }
    }

    //removes selected songs from the songsListBox and also the playListBox
    private void removeSongsButton_Click(object sender, EventArgs e)
    {
        if (selectedSong != null && songsListBox.SelectedItems.Contains(selectedSong.Name))
        {
            StopPlayback();
            selectedSong = null;
        }

        for (int i = songsListBox.SelectedItems.Count; i > 0; i--)
        {
            string selectedSongName = songsListBox.SelectedItems[i - 1].ToString();

            songsListBox.Items.Remove(selectedSongName);
            playListBox.Items.Remove(selectedSongName);
            songs.Remove(selectedSongName);
        }
    }

    private void playListBox_SelectedIndexChanged(object sender, EventArgs e)
    {
        if (playListBox.SelectedItem != null &&
            songs[playListBox.SelectedItem.ToString()] != selectedSong)
        {
            StopPlayback();
            selectedSong = songs[playListBox.SelectedItem.ToString()];
        }
    }

    private void playButton_Click(object sender, EventArgs e)
    {
        if (selectedSong != null)
        {
            player = new SoundPlayer(selectedSong.FullPath);
            player.Play();
        }
    }

    private void stopButton_Click(object sender, EventArgs e)
    {
        StopPlayback();
    }

    private void StopPlayback()
    {
        if (player != null)
        {
            player.Stop();
            player.Dispose();
        }
    }

    //adds songs selected in the songsListBox to the playListBox
    private void addToPlaylistButton_Click(object sender, EventArgs e)
    {
        for (int i = 0; i < songsListBox.SelectedItems.Count; i++)
        {
            // the if statement checks if playListBox already
            // contains a song with this name before adding it.
            if (!playListBox.Items.Contains(songsListBox.SelectedItems[i]))
            {
                playListBox.Items.Add(songsListBox.SelectedItems[i]);
            }
        }
    }

    //removes selected song from the playListBox
    private void removeFromPlaylistButton_Click(object sender, EventArgs e)
    {
        if (selectedSong != null && selectedSong.Name == playListBox.SelectedItem.ToString())
        {
            StopPlayback();
            selectedSong = null;
        }

        playListBox.Items.Remove(playListBox.SelectedItem);
    }

    //removes all songs from the playListBox
    private void clearPlaylistButton_Click(object sender, EventArgs e)
    {
        if (selectedSong != null)
        {
            StopPlayback();
            selectedSong = null;
        }

        playListBox.Items.Clear();
    }
}

class Song
{
    internal string FullPath { get; private set; }
    internal string Directory { get; private set; }
    internal string Name { get; private set; }

    public Song(string path)
    {
        FullPath = path;
        Directory = System.IO.Path.GetDirectoryName(path);
        Name = System.IO.Path.GetFileNameWithoutExtension(path);
    }
}
 
Share this answer
 
v7
Comments
Joel Whatley- 28-Jan-12 21:21pm    
I love you. I actually do!
It works! Finally!!
:happy:

Just 1 thing:)
In my original program there were 2 list boxes.
The first one was to enter songs into via the dialog.
The second was the proper music list you moved the songs you want from the first one.

For example:

listBox2.Items.Add(listBox1.Items[listBox1.SelectedIndex].ToString());
listBox1.Items.Remove(listBox1.Items[listBox1.SelectedIndex].ToString());

Is there a way to do this ? :)
LanFanNinja 28-Jan-12 21:33pm    
"Is there a way to do this ?"
Yes.

Give me a little bit and check back.
Joel Whatley- 28-Jan-12 21:43pm    
You're the best!!
LanFanNinja 28-Jan-12 22:38pm    
OK recheck my solution for the latest revision.
Joel Whatley- 28-Jan-12 23:12pm    
Alright. Thank you so much for your help, you made my week!
You are ridiculously helpful.
<3:)
Something like this should work for you. If you have any questions just ask and I will try to help you.

NOTE: I did not try to run this code so it could contain an error or two. Let me know if this is the case and I will help you figure it out.

C#
class Song
{
    internal string Name { get; private set; }
    internal string FullPath { get; private set; }
    internal string Directory { get; private set; }

    public Song(string path)
    {
        FullPath = path;
        Name = Path.GetFileNameWithoutExtension(path);
        Directory = Path.GetDirectoryName(path);
    } 
}

// * NOTE: openSongDialog is of the type OpenFileDialog *
class Form1 : Form
{
    List<Song> songs = new List<Song>();

    if (openSongDialog.ShowDialog() == DialogResult.OK)
    {
        Song song = new Song(openSongDialog.FileName);
       
        songs.Add(song);
    }
}


EDIT:
After thinking about this some more I realized you would probably be better off to use a Dictionary instead.

Using a Dictionary would allow you to index songs using the songs name from the ListBox.

Here is an example:

C#
class Form1 : Form
{
    Dictionary<string, Song> songs = new Dictionary<string, Song>();

    if (openSongDialog.ShowDialog() == DialogResult.OK)
    {
        Song song = new Song(openSongDialog.FileName);
       
        songs.Add(song.Name, song);
    }
}


Then you could do something like this to get the song selected in the ListBox.
C#
Song selectedSong = songs[songListBox.SelectedItem.ToString()];
 
Share this answer
 
v8
Comments
Sergey Alexandrovich Kryukov 27-Jan-12 22:22pm    
Good enough, but:
1) using public is not justified; public is only needed if the types and members are to be accessible from some referencing assembly;

2) Names like Form1, listBox1 are not acceptable from the style and maintenance point of view; whatever Designer auto-generate violate (good) Microsoft naming conventions, should always be renamed to give some semantic names.

3) Three string fields are totally redundant. You could either store name and path (and compose fill name when needed), or only store full name and extract whatever needed on the fly. You could use three string properties though, but getter should be implemented based on just one fields (or two fields).

4) Private set is redundant -- you never use it, should cause warning. I was convinced that this usage is just fine, please see our comments below -- thank you.

I voted 4.

Cheers,
--SA
LanFanNinja 27-Jan-12 22:28pm    
Thanks for the vote.

"using public is not justified"
Should I have used protected instead?

"Names like Form1, listBox1 are not acceptable"
This was only an example however I agree I should have used more meaningful names.
Sergey Alexandrovich Kryukov 27-Jan-12 22:45pm    
Of course not protected (it is the access for ancestors only). You should use "internal". This is the same as "public" but limit access to the assembly where the types/members are declared. Do yourself a pretty good fair and review all 4 access types again. Then you will add to your arsenal "internal" and "internal protected" (instead of protected).

You should not give more access then it is really required.

The names for example? Right, you can do it, but the problem is: inquirers will not understand that it was just for example, they will likely follow your lead as the expert and might think this is acceptable. It's always better not to set a wrong model for the students. Moreover, giving good names is not harder than bad once. (After all, this is the one of the main uses of the Refactoring Engine of VS.)
Call them "MyForm", "MainForm", "listBoxSongs"; and everyone will understand it.

Thank you for attention.
--SA
LanFanNinja 27-Jan-12 22:49pm    
Sorry my bad I meant to write internal and not protected. I have been on hiatus for three weeks and I think I must have misplaced my mind somewhere! :)

Thank you for the info and suggestions.
LanFanNinja 27-Jan-12 23:22pm    
I have changed the properties access modifiers from public to internal as per your suggestion.

EDIT:
Also changed my variable names to be a little more meaningful as well.
Although you create each Song class 'on the fly' (note singular, Song) you should have a collection intowichnyou add each newly created Song object - I'd call that class Songs.

C#

Public Class Songs : List<song>

So now you have a reference to the objects you are creating...

Also,your three properties should probably only be 2 - the file name and the path - with perhaps the fulfills pathname property concatenation the other properties - rather than actually storing duplicate data internally. (if it is homework y'd lose marks for that. ;)

Excuse the typing and formatting, I'm on the iPad and the popup for formatting is stuck open so I can't see what I am typing
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900