2008-11-08 8 views
3

Auparavant, j'avais une classe qui contenait un System.Collections.Generic.List<Item> interne (où Item est une classe que j'ai créée). La classe wrapper fournissait plusieurs propriétés au niveau de la collection qui fournissaient des totaux, des moyennes et d'autres calculs sur les éléments de la liste. Je créais un BindingSource autour de ce List<> enveloppé et un autre BindingSource autour de ma classe et j'étais capable d'obtenir les éléments dans la liste enveloppée par le premier BindingSource et les propriétés au niveau de la collection de la classe wrapper en utilisant la seconde.Comment puis-je indexer des données sur des propriétés non associées à un élément de liste dans les classes dérivées? <T>

Un exemple simplifié ressemble:

public class OldClass() 
{ 
    private List<Item> _Items; 

    public OldClass() 
    { 
    _Items = new List<Item>(); 
    } 

    public List<Item> Items { get { return _Items; } } 

    // collection-level properties 
    public float AverageValue { get { return Average() } } 
    public float TotalValue { get { return Total() } } 
    // ... other properties like this 

} 

Avec les sources de liaison créées de cette façon:

_itemsBindingSource = new BindingSource(oldClass.Items); 
_summaryBindingSource = new BindingSource(oldClass); 

Récemment, j'ai essayé de changer cette classe à tirer de System.Collections.Generic.List<Item> au lieu de garder une enveloppé List<> membre. Mon espoir était de se débarrasser de la couche d'emballage supplémentaire et d'utiliser seulement un BindingSource au lieu de deux. Cependant, maintenant je trouve que je ne peux pas obtenir les propriétés qui s'appliquent à tous les éléments de la liste (tels que AverageValue) lorsque je fais une liaison de données. Seules les propriétés des éléments de liste sont disponibles.

Suis-je obligé de revenir à l'utilisation d'un List<> de Item s? Ou y at-il un moyen que je peux obtenir à la fois les propriétés de Item s stocké ma nouvelle classe ainsi que les propriétés qui s'appliquent à la collection elle-même?

Répondre

5

Le système traite tout ce qui implémente IList (ou IListSource) en tant que conteneur plutôt qu'en tant qu'élément. En tant que tel, vous ne pouvez pas lier à des propriétés de tout ce qui implémente IList. En tant que tel, encapsulation (c'est-à-dire ce que vous avez déjà) est la meilleure approche si vous voulez être capable de se lier aux propriétés du conteneur. Cependant, vous devez noter que de nombreuses liaisons prennent en charge la notation par points dans la source, c'est-à-dire soit la liaison à "Items.SomeProperty", soit la définition de la propriété auxiliaire (généralement DataMember) pour spécifier des sous-listes.

Cela vous permet d'avoir un seul BindingSource, et ont différents contrôles liés à différents niveaux dans la hiérarchie - à savoir que vous pourriez avoir un TextBox lié à AverageValue, et un DataGridView (avec le même DataSource) qui a DataMember="Items".

0

Le problème ici est que vous voulez utiliser votre classe à deux fins complètement différentes (en termes de liaisons). Exemple: La propriété "AverageValue" n'a pas de sens d'être sur chaque élément, car il s'agit d'une propriété globale qui couvre tous les éléments.

De toute façon, je suppose que votre _itemsBindingSource est pour un ComboBox ou quelque chose, et que votre _summaryBindingSource est pour un PropertyGrid (ou quelque chose comme ça).

Qu'est-ce que vous pourriez faire, ce pourrait travailler dans votre situation (je ne peux pas être certain parce que je ne sais pas ce que vous faites en réalité) est la suivante:

1) Faites votre " OldClass "implémente IEnumerable ... et dans ce cas, renvoie simplement l'énumération de la liste. Cela vous donnera la possibilité de lier à "oldClass" au lieu de "oldClass.Items".

2) Faites des "éléments de liste publique" un champ au lieu d'une propriété ... ou ajoutez l'attribut "Browsable (false)" afin qu'il ne soit pas lié au PropertyGrid (c'est une supposition car c'est pas clair ce que vous utilisez ces liaisons pour).

0

Au lieu de créer une classe wrapper autour de votre liste, avez-vous envisagé la création d'une classe d'extension (en supposant que vous utilisez C# 3)

public static class MyExtensions 
{ 
    public static float GetAverage(this List<Item>) 
    { 
     // implementation 
    } 

    public static float GetTotal(this List<Item>) 
    { 
     // implementation 
    } 
} 

Bien sûr, vos propriétés deviennent les appels de méthode (maybe C# 4 will fix this), mais vous élimineriez complètement l'emballage.