如何根据类属性过滤不同的东西?

时间:2010-01-03 23:33:57

标签: c# wpf xml

这是我要做的事情的要点。

Heres'我的英雄课:

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;
        }
    }
}

该类的每个属性都是XML元素。我已将所有信息手动制表成XML文件,以便将其反序列化为Hero类,并将实例转发到需要的地方。

有一个用例我无法理解。

我有两个按钮,ViewGood和ViewEvil。

Hero类中有一个名为Faction的属性,我必须过滤掉哪些英雄有好,哪些英雄有邪恶。

我在想做什么:

  1. 我有一个循环的方法 通过XML和中的每个节点 返回包含所有的List 英雄姓名与要求的HEROTYPE相匹配。

  2. 使用该列表,我可以 做一个foreach和所有英雄 在窗体上有一个Image控件 使用x:名称设置为英雄 名字,我可以做.Visibilty = Visibility.False给所有人,并设置它 忠实于每个英雄的名字 名单。有效隐藏每个Image控件 这不在名单上。

  3. 我向你们提问的是,我做的事情是完全迟钝的吗?我真的想花更多的时间让这个程序有很好的干净代码,因为我想学习比什么都重要。

    正如我父亲所说,“坏习惯很容易学习,强奸你的好习惯。”

    非常感谢。 :)

4 个答案:

答案 0 :(得分:4)

我不明白。您想要一个按属性过滤的列表吗?

喜欢这个吗?

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

编辑以回答评论:

  

你的第二行是否相当于做一个foreach并询问是否hero.Faction ==“Jedi”

或多或少,是的。在大多数情况下,它的行为相同,但底层LINQ的行为完全不同。如果您喜欢这种语法,我建议您阅读本文或查看本网站上的LINQ问题。

可以咬你的主要差异是默认情况下这是懒惰的。

Where(hero => hero.Faction == "Jedi")会返回IEnumerable<Hero>并且实际上不会按照您的要求执行操作,除非您真正手动或通过将结果转换为列表来迭代枚举器:

Where(hero => hero.Faction == "Jedi").ToList()可能会做你想要的第一个:这给你一个已经代表过滤结果的列表。

但请注意保持懒惰,这在后面非常有用,例如当你构造和嵌套多个像这样的“查询”时。

答案 1 :(得分:1)

您是否希望针对XML进行一些查询?你想要XPath:http://www.w3schools.com/XPath/default.asp&amp; http://www.codeproject.com/KB/cpp/myXPath.aspx

答案 2 :(得分:1)

在WPF中执行此操作的一种简单方法是使用CollectionView而不是原始列表作为ItemsSource。然后,您可以在此设置过滤器,列表控件将仅显示通过过滤器的项目。

但是,听起来您将图像控件直接添加到Panel(Canvas?)而不是使用列表控件。在这种情况下,迭代Image控件并设置其可见性是一种方法。另一种方法是创建一个视图模型类,它使用可见性等显示属性来扩充Hero类,并在用户选择不同的视图按钮时更新该可见性。然后,您的图像控件可以将其可见性数据绑定到视图模型可见性。在视图模型中执行此操作而不是直接操作Image控件的优点是可测试性:对于这样的简单案例而言并不是一件大事,但对于复杂的应用程序而言则越来越重要。

顺便说一句,如果您目前正在手动添加图像但是您的设计还没有设置,我强烈建议使用ItemsControl来调查处理集合的显示。 (请记住,ListBox不仅仅是一个垂直堆栈:您可以使用它来显示您选择的任何布局中的内容。)这将删除大量繁琐的迭代代码!

答案 3 :(得分:0)

如果您不打算使用itowlson建议使用CollectionView(有利弊),另一种处理方法是在您的班级中添加IsVisible属性然后实施INotifyPropertyChanged。然后在WPF中支持show / hide非常容易:

<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}"/>

(您可能会使用Grid而不是StackPanel;这只是为了显示DataTemplate对象的Hero可能是什么样的。)

IsVisible属性必须属于Visibility类型,而不是布尔值,除非您想要实现一个值转换器来将true转换为Visibility.Visible和{{ 1}}到false,例如this guy did

一旦你这样做,做这样的事情:

Visibility.Collapsed

将像魔术一样工作。 (如果您已实现foreach (Hero h in HeroesCollection) { h.IsVisible = h.Faction == selectedFaction ? Visiblity.Visible : Visibility.Collapsed; } 。如果您没有实现,则不会发生任何事情,因为UI不会知道INotifyPropertyChanged属性已更改。)