如何在 WPF 中将自定义对象绑定到 ListBox
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15228741/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to bind Custom Object to ListBox in WPF
提问by pblyt
I am new to WPF so please accept my apologies if my question is stupid.
我是 WPF 的新手,所以如果我的问题很愚蠢,请接受我的道歉。
I am creating a food ordering system which consists of 2 main sections, the "Food Menu" and the "Order List". When user chooses an item from the food menu, it will be added to the a listbox control which represents the order list.
我正在创建一个食品订购系统,它由 2 个主要部分组成,“食品菜单”和“订单列表”。当用户从食物菜单中选择一个项目时,它将被添加到代表订单列表的列表框控件中。
I have created a few custom objects: Order, OrderLine, Item, as well as a Collection class, OrderLineCollection, for "OrderLine". They look like the following:
我为“OrderLine”创建了一些自定义对象:Order、OrderLine、Item以及 Collection 类OrderLineCollection。它们如下所示:
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; }
}
My ListBoxcontrol has a DataTemplateso that more details are shown for each item. The XAML as below:
我的ListBox控件有一个,DataTemplate以便为每个项目显示更多详细信息。XAML 如下:
<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>
so when items are added, the ListBox will look like the below image: https://dl.dropbox.com/u/6322828/orderList.png
所以当添加项目时,ListBox 将如下图所示:https: //dl.dropbox.com/u/6322828/orderList.png
In the code-behind, I have created a static variable currentOrderfor storing the current order and it will be used by other classes/methods.
在代码隐藏中,我创建了一个currentOrder用于存储当前订单的静态变量,它将被其他类/方法使用。
And every time its value is changed, the following stupid method LoadCurrentOrder()is called to refresh the ListBox view.
并且每次更改其值时,LoadCurrentOrder()都会调用以下愚蠢的方法来刷新 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);
}
}
My problem is how can I bind the data in an elegant way (such as using ResourcesItemsSourceand so on) instead of using the above method, so that the ListBox will update automatically every time the value of the variable is changed?
我的问题是如何以优雅的方式(例如使用ResourcesItemsSource等等)绑定数据而不是使用上面的方法,以便每次更改变量的值时ListBox都会自动更新?
I tried
我试过
lbxOrder.ItemsSource = currentOrder;
but it does not work as currentOrder is not a System.Collections.IEnumerableobject.
但它不起作用,因为 currentOrder 不是一个System.Collections.IEnumerable对象。
回答by Federico Berasategui
1 - Don't create your own collection types, the .Net framework Base Class Library already has pretty much everything you need.
1 - 不要创建自己的集合类型,.Net 框架基类库已经拥有您需要的几乎所有内容。
Remove the OrderLineCollectionand use an ObservableCollection<OrderLine>.
删除OrderLineCollection并使用ObservableCollection<OrderLine>.
2 - Try to stick to MVVM conventions. This means you should not manipulate UI elements in code.
2 - 尝试遵守 MVVM 约定。这意味着您不应在代码中操作 UI 元素。
public OrderList()
{
InitializeComponent();
LoadCurrentOrder();
DataContext = this;
}
then in XAML:
然后在 XAML 中:
<ListBox ItemsSource="{Binding LineItems}" HorizontalContentAlignment="Stretch">
3 - Do not name UI elements in XAML unless you need to reference them in XAML. This will help you reconsider your approach every time you find yourself wanting to manipulate UI elements in procedural code.
3 - 不要在 XAML 中命名 UI 元素,除非您需要在 XAML 中引用它们。这将帮助您在每次发现自己想要在程序代码中操作 UI 元素时重新考虑您的方法。
4 - Get used to the C# naming convention. Property names should be "proper cased" (I.E LineItemsinstead of lineItems)
4 - 习惯 C# 命名约定。属性名称应该是“适当的大小写”(IELineItems而不是lineItems)
回答by dutzu
All you have to do is to make the lineItemsproperty into an ObservableCollection<yourType>. Then when this collection is changed (items added, removed) the listbox will refresh automatically.
您所要做的就是将该lineItems属性转换为ObservableCollection<yourType>. 然后,当此集合发生更改(添加、删除项目)时,列表框将自动刷新。
If your problem is that the order itself changes and you need to refresh the listbox. Then all you need to do is to implement INotifyPropertyChangedand when the order changes, to trigger the notification that the property has changed and the UI will refresh via the binding.
如果您的问题是订单本身发生了变化,您需要刷新列表框。然后你需要做的就是实现INotifyPropertyChanged,当订单改变时,触发属性改变的通知,UI将通过绑定刷新。
As for the binding in a more elegant way. You can bind to the currentOrder.lineItems:
至于以更优雅的方式绑定。您可以绑定到currentOrder.lineItems:
lbxOrder.ItemsSource = currentOrder.lineItems;//this should be an observable collection if you intend to have items change

