tags:

views:

61

answers:

4

Here's the gist of what I'm going to do.

Heres' my hero class:

namespace TomeOfNewerth_WPF_
{
    public enum HeroType
    {
        Agility,
        Strength,
        Intelligence
    }

    public enum AttackType
    {
        Melee,
        Ranged,
    }

    class Hero
    {
        public string Faction;
        public string Name;
        public HeroType HeroType;
        public string Backstory;
        public double MinimumDamage;
        public double MaximumDamage;
        public double Armor;
        public double MoveSpeed;
        public AttackType AttackType;
        public double AttackRange;
        public double AttackRate;
        public int Strength;
        public int Agility;
        public int Intelligence;
        public string DOTAVersion;

        //Default constructer required for XML serialization.
        public Hero()
        { }

        /// <summary>
        /// This method returns a hero full of the necessary information.
        /// </summary>
        /// <param name="Name">Name of the hero.</param>
        /// <returns>Returns an instace of the Hero class chock full of information.</returns>
        public Hero GetHero(string Name)
        {
            Hero NewHero = new Hero();

            NewHero.Faction = "Legion";
            NewHero.Name = "Andromeda";
            //Yada yada yada. I have to complete this, so disregard it.

            return NewHero;
        }
    }
}

Each attribute of that class is an XML element. I have manually tabulated all the information into an XML file so I can deserialize it into the the Hero class and forward the instance to wherever it is needed.

There is one use case that I can't really get my head around.

I have two buttons, ViewGood and ViewEvil.

There is an attribute on the Hero class called Faction and I have to filter out which Heroes have Good and which heroes have Evil.

What I'm thinking of doing:

  1. I'd have a method that cycles through each node in the XML and return a List containing all the hero names which match the HEROTYPE that was asked for.

  2. Using that List, I can then do a foreach and since all Heroes have an Image control on the form with the x:Name set as the Hero name, I can do a .Visibilty = Visibility.False to all, and set it to true to every hero name on the list. Effectively hiding every Image control that is not on the List.

My question to you guys is, am I doing something completely retarded? I really want to take extra time and make this program have nice clean code because I want to learn more than anything.

As my father said, 'Bad habits are easy to learn, it's the good ones that rape you.'

Thanks SO. :)

+4  A: 

I don't get it. You want a list filtered by an attribute?

Like this?

List<Hero> heroes = GetYourHeroes();
var goodGuys = heroes.Where(hero => hero.Faction == "Jedi");

Edit to answer the comment:

Would you second line be equivalent to doing a foreach and asking if hero.Faction == "Jedi"

More or less, yes. For most purposes it would behave the same, but the underlying LINQ behaves quite differently. I suggest you read about it or check the LINQ questions on this site if you like this syntax.

The major difference that can bite you is that this is lazy by default.

Where(hero => hero.Faction == "Jedi") returns an IEnumerable<Hero> and won't actually do what you want unless you really iterate the enumerator, either manually or by converting the result into a list:

Where(hero => hero.Faction == "Jedi").ToList() would probably do what you expected to have in the first place: This gives you a list that already represents the filtered result.

Keep the lazyness in mind though, it is quite useful lateron, for example when you construct and nest multiple "Queries" like these.

Benjamin Podszun
Hi Pap, Ben's answer uses something called LINQ, which essentially allows you to execute queries against object collections. It's perfect for what you are doing.
CraigS
Hi there Benjamin. Would you second line be equivalent to doing a foreach and asking if hero.Faction = "Jedi"? If so, that is so SEXY.
Sergio Tapia
The result is the same thing but it's implemented in a more optimized way, so it will perform better. Or at least i think it is!
Paul Creasey
Paul: I'm pretty sure it won't perform better. Under the covers, .Where is just enumerating using an IEnumerator, exactly the same as foreach does.
itowlson
Nonetheless, it is indeed sexy.
Robert Rossney
@Ben - what you're missing is that he doesn't know something you do (or at least didn't). @Papuccino - learn Linq, Linq to objects will help you in code and Linq to XML will be a huge help in dealing with XML if you get to a point where serialization won't do (or for other things).
Murph
+1  A: 

Are you looking to do some queries against the XML? You want XPath: http://www.w3schools.com/XPath/default.asp & http://www.codeproject.com/KB/cpp/myXPath.aspx

Noon Silk
+1  A: 

One simple way of doing this in WPF is to use a CollectionView instead of a raw list as your ItemsSource. You can then set a filter on this, and your list control will show only the items that pass the filter.

However, it sounds like you are adding Image controls directly to a Panel (a Canvas?) rather than using a list control. In this case, iterating over the Image controls and setting their visibility is one approach. Another is to create a view model class which augments the Hero class with display attributes such as Visibility, and to update that Visibility as the user selects different view buttons. Your Image controls can then databind their Visibility to the view model Visibility. The advantage of doing this in a view model rather than manipulating the Image controls directly is testability: not a big deal for a simple case like this, but increasingly important with complex applications.

By the way, if you are currently adding Images by hand but your design is not set in stone yet, I'd strongly advise investigating using an ItemsControl to handle the display of the collection. (Remember, a ListBox is not just a vertical stack: you can use it to display things in any layout you choose.) This will remove a lot of tedious iteration code!

itowlson
A: 

If you're not going to use itowlson's suggestion of using a CollectionView (there are pros and cons), another way to handle this is by adding a IsVisible property to your class and then implementing INotifyPropertyChanged. Then supporting show/hide in WPF is extremely easy:

<DataTemplate DataType="{x:Type local:Hero}">
   <StackPanel Orientation="Horizontal" IsVisible="{Binding IsVisible}">
      <TextBlock Text="{Binding Faction}"/>
      <TextBlock Text="{Binding Name}"/>
         ... etc.
   </StackPanel>
</DataTemplate>

<ListBox ItemsSource="{Binding MyDataSource.HeroesCollection}"/>

(You would probably use a Grid rather than a StackPanel; that's just to show what a DataTemplate for a Hero object might look like.)

It's important that the IsVisible property be of type Visibility, and not boolean, unless you feel like implementing a value converter to convert true to Visibility.Visible and false to Visibility.Collapsed, like this guy did.

Once you do this, doing something like this:

foreach (Hero h in HeroesCollection)
{
   h.IsVisible = h.Faction == selectedFaction 
      ? Visiblity.Visible 
      : Visibility.Collapsed;
}

will work like magic. (If you've implemented INotifyPropertyChanged. If you haven't, nothing will happen, because the UI won't know that the Visibility property changed.)

Robert Rossney