views:

81

answers:

4

Special thanks to Rex M for this bit of wisdom:

        public IEnumerable<Friend> FindFriends()
        {
            //Many thanks to Rex-M for his help with this one.
            //http://stackoverflow.com/users/67/rex-m

            return doc.Descendants("user").Select(user => new Friend
            {
                ID = user.Element("id").Value,
                Name = user.Element("name").Value,
                URL = user.Element("url").Value,
                Photo = user.Element("photo").Value
            });
        }

After finding all of a users friends, I need to show them on a WPF form. I have a problem that not all users have at least 5 friends, some even have no friends! Here's what I have:

        private void showUserFriends()
        {
            if (friendsList.ToList().Count > 0)
            {
                friend1.Source = new BitmapImage(new Uri(friendsList.ToList()[0].Photo));
                label11.Content = friendsList.ToList()[0].Name;

                friend2.Source = new BitmapImage(new Uri(friendsList.ToList()[1].Photo));
                label12.Content = friendsList.ToList()[1].Name;

                //And so on, two more times. I want to show 4 friends on the window.
            }            
        }

So this question has two parts:

  1. How do you suggest I handle the varying number of friends a user might have. With my current code if a user has no friends I get an IndexOutOfBounds exception because friendsList[0] doesn't exist.

  2. How can I more efficiently handle the validation of whether or not a user has friends? Calling .ToList() seems very taxing.

+2  A: 

1) Databind the friends list to a ListBox. You can use data templates to display images and labels.

2) Call Any().

Stephen Cleary
+2  A: 

In this case just call ToList() once before the if statement rather than creating a list everytime.

EDIT

You might want to look at the MVVM pattern and have XAML to bind the controls to the data

aqwert
this is a good local optimization. however, it's not even necessary to convert to list, since the OP already has an `IEnumerable`, which can be iterated over using `foreach`.
Franci Penov
Ah yes that is true
aqwert
Although it by the looks he has statically created friend1, friend2 etc which could make it difficult when using foreach as there would have to be additional conditional checks as to the index you are looking at. My first suggestion kept the amount of changes to a simple refactoring
aqwert
+1  A: 

Use some kind of ItemContainer control, such as any ItemsControl. You just specify a template for what the item should look like, and set its ItemsSource property:

myItemsControl.ItemsSource = new ObservableCollection(myFriends.Take(4));

This will show up to 4 friends, repeating the template as many times as it needs to, but as few as 0 if the collection is empty.

Rex M
+1  A: 

When you call ToList() on an IEnumerable what you are doing is Enumerating all the elements of the enumerable list and placing the results into a container. So a "code smell" is code that call's ToList() multiple times on the same IEnumerable, it should only be done once and saved to a variable.

There is a simple rule of thumb. If you are operating on the IEnumerable list as a whole (Linq expressions) or simply navigating the list from start to finish then use IEnumerable, if you need to access a list by index, or count the number of elements or navigate both directions through the list, create a List container first and use it.

i.e.

List<Friend> friends = FindFriends().ToList();
//Then use the friends list....

Now, with regards to if there is anything in your list or not, as a couple people here have mentioned, you can use data binding and a control like ItemsControl, but if you do want to build UI stuff up dynamically use a loop, don't index into the array.

List<Friend> friends = FindFriends().ToList();
if(friends.Count > 0)
{
  foreach(Friend f in friends)
  {
    //Create your Control(s) and add them to your form or panel's controls container
    // somthing like (untested) myPanel.Controls.Add(new Label(){Text = f.Name});
  }
}
Tim Jarvis