2013-03-05 2 views
1

Je suis nouveau à WPF alors s'il vous plaît accepter mes excuses si ma question est stupide.Comment lier l'objet personnalisé à ListBox dans WPF

Je crée un système de commande alimentaire qui se compose de 2 sections principales, le "Menu Alimentaire" et la "Liste de Commande". Lorsque l'utilisateur choisit un élément du menu des aliments, il sera ajouté au contrôle de la liste qui représente la liste des commandes.

J'ai créé quelques objets personnalisés: Order, OrderLine, Item, ainsi qu'une classe de collection, OrderLineCollection, pour "OrderLine". Ils ressemblent à ce qui suit:

public class Order 
{ 
    public string ID { get; set; } 
    public DateTime DateTime { get; set; } 
    public double TotalAmt { get; set; } 
    public OrderLineCollection LineItems { get; set; } 
} 

public class OrderLine 
{ 
    public Item Item { get; set; } 
    public double UnitPrice { get; set; } 
    public int Quantity { get; set; } 
    public double SubTotal { get { return unitPrice * quantity; } } 
} 

[Serializable] 
public class OrderLineCollection : CollectionBase 
{ 
    public OrderLine this[int index] 
    { 
     get { return (OrderLine)List[index]; } 
     set { List[index] = value; } 
    } 
} 

public class Item 
{ 
    public string ID { get; set; } 
    public string Name { get; set; } 
    public string Description { get; set; } 
    public double UnitPrice { get; set; } 
    public byte[] Image { get; set; } 
} 

Mon ListBox contrôle a un DataTemplate de sorte que plus de détails sont présentés pour chaque élément. Le XAML comme ci-dessous:

<Page x:Class="FoodOrdering.OrderList" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="Order List"> 
    <ListBox Name="lbxOrder" HorizontalContentAlignment="Stretch">    
     <ListBox.ItemTemplate> 
      <DataTemplate> 
       <Grid Margin="5"> 
        <Grid.ColumnDefinitions> 
         <ColumnDefinition Width="*"/> 
         <ColumnDefinition Width="30"/> 
         <ColumnDefinition Width="80"/> 
        </Grid.ColumnDefinitions> 
        <Grid.RowDefinitions> 
         <RowDefinition/> 
         <RowDefinition Height="40"/> 
        </Grid.RowDefinitions> 
        <TextBlock Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" Text="{Binding item.name}"/> 
        <TextBlock Grid.Row="0" Grid.Column="1" Text="x "/> 
        <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding quantity}" Margin="10,0,0,0"/> 
        <TextBlock Grid.Row="0" Grid.Column="2" Text="{Binding subTotal, Converter={StaticResource priceConverter}}" HorizontalAlignment="Right"/> 
        <Button Grid.Row="1" Grid.Column="2" Margin="0,5,0,0" Click="btnDelete_Click">Delete</Button> 
       </Grid> 
      </DataTemplate> 
     </ListBox.ItemTemplate> 
    </ListBox> 
</Page> 

donc lorsque des éléments sont ajoutés, la zone de liste ressemblera à l'image ci-dessous: https://dl.dropbox.com/u/6322828/orderList.png

Dans le code-behind, j'ai créé une currentOrder variable statique pour stocker les commande en cours et il sera utilisé par d'autres classes/méthodes.

Et chaque fois que sa valeur est modifiée, la méthode stupide suivante LoadCurrentOrder() est appelée pour actualiser la vue ListBox.

public partial class OrderList : Page 
{ 
    public static Order currentOrder = new Order(); 
    public OrderList() 
    { 
     InitializeComponent(); 
     LoadCurrentOrder(); 
    } 

    public void LoadCurrentOrder() 
    { 
     lbxOrder.Items.Clear(); 
     foreach (OrderLine ol in currentOrder.LineItems) 
      lbxOrder.Items.Add(ol); 
    } 
} 

Mon problème est comment puis-je lier les données d'une manière élégante (comme l'utilisation ResourcesItemsSource, etc.) au lieu d'utiliser la méthode ci-dessus, de sorte que la zone de liste se mettra à jour automatiquement à chaque fois que la valeur de la variable est changé?

J'ai essayé

lbxOrder.ItemsSource = currentOrder; 

mais il ne fonctionne pas comme currentOrder est pas un objet System.Collections.IEnumerable.

Répondre

4

1 - Ne pas créer vos propres types de collections, le framework .Net Base Class Library a déjà à peu près tout dont vous avez besoin.

Supprimez le OrderLineCollection et utilisez un ObservableCollection<OrderLine>.

2 - Essayez de respecter les conventions MVVM. Cela signifie que vous ne devez pas manipuler les éléments de l'interface utilisateur dans le code.

public OrderList() 
{ 
    InitializeComponent(); 
    LoadCurrentOrder(); 
    DataContext = this; 
} 

puis en XAML:

<ListBox ItemsSource="{Binding LineItems}" HorizontalContentAlignment="Stretch"> 

3 - Ne pas nommer les éléments de l'interface utilisateur en XAML, sauf si vous avez besoin de les référencer dans XAML. Cela vous aidera à reconsidérer votre approche chaque fois que vous aurez besoin de manipuler des éléments de l'interface utilisateur dans le code de procédure.

4 - Habituez-vous à la convention de dénomination C#. Les noms de propriété doivent être "correctement encadrés" (I.E LineItems au lieu de lineItems)

+0

Merci pour les conseils de convention en particulier le nom, devinez que j'ai désordonné le concept depuis longtemps ... J'ai édité les noms de propriété au cas où d'autres pourraient être confus 'ObservableCollection' fonctionne très bien dans mon projet WPF. Mais que faire si je crée les classes dans un projet de bibliothèque de classes? J'ai essayé et il semble que 'ObservableCollection' ne supporte que l'utilisation de XAML? – pblyt

+0

@pblyt la classe ['System.Collections.ObjectModel.ObservableCollection '] (http://msdn.microsoft.com/en-us/library/ms668604 (v = vs.100) .aspx) est définie dans la ' L'assembly System.dll, donc c'est une partie centrale du .Net BCL, il n'est en aucun cas dépendant des assemblages WPF ou des classes. –

0

Tout ce que vous avez à faire est de faire la propriété lineItems dans un ObservableCollection<yourType>. Ensuite, lorsque cette collection est modifiée (éléments ajoutés, supprimés), la liste déroulante sera automatiquement actualisée.

Si votre problème est que la commande elle-même change et que vous avez besoin d'actualiser la liste. Ensuite, tout ce que vous devez faire est de mettre en œuvre INotifyPropertyChanged et lorsque la commande change, pour déclencher la notification que la propriété a changé et l'interface utilisateur se rafraîchira via la liaison.

Comme pour la reliure d'une manière plus élégante. Vous pouvez lier à la currentOrder.lineItems:

lbxOrder.ItemsSource = currentOrder.lineItems;//this should be an observable collection if you intend to have items change 
+0

Merci @dutzu, 'ObservableCollection' fonctionne correctement dans mon projet WPF. Mais que faire si je crée les classes dans un projet de bibliothèque de classes et que je l'ajoute comme référence dans le projet WPF? J'ai essayé et il semble que 'ObservableCollection' ne supporte que l'utilisation de XAML. – pblyt

+0

Vous pouvez toujours placer une liste d'objets que vous recevez de la bibliothèque de classes en tant que ObservableCollection pour répondre à vos besoins d'interface utilisateur. – dutzu