我正在构建一个N层WPF应用程序。 我想要零代码隐藏。
假设我有 3 个规范化的相关表来记录销售交易。
交易:
事务 ID, ItemId, 供应商编号, 价格
供应商:
供应商编号, 供应商名称
项目:
ItemId, 项名称。
对于每个表,我都有一个反映字段的基类。 然后是根据需要填充基本对象集合的数据层。
我想在页面上有一个列表框,显示所有事务的列表,每行 1 个事务,这些行应该看起来像这样......
"Trainers FootLocker €99"
"Trousers TopShop €45"
"Coat TopShop €49"
如果我使用
<ListBox
ItemsSource="{Binding Path=Transactions}"
SelectedItem="{Binding CurrentTransaction}"
然后我最终得到发生业务表中的 ID 行,而不是物料和供应商表中的名称值。
鉴于我有仅填充其他表的 ID 的事务集合,填充列表框的最佳方法是什么?
我想知道的一件事是,我的事务基对象是否应该包含填充在那里的项项而不是整型项 ItemId?
事务基础模型:
using System;
using System.ComponentModel;
using PFT;
using PFT.Data;
namespace PFT.Base
{
public class Transaction : INotifyPropertyChanged
{
public int Id { get; set; }
private int _itemId;
public int ItemId
{
get { return _itemId; }
set {
_itemId = value;
ItemData id = new ItemData();
this.Item = id.Select(value);
NotifyPropertyChanged("ItemId");
}
}
private Item _item;
public Item Item
{
get { return _item; }
set { _item = value; }
}
private float _price;
public float Price
{
get { return _price; }
set {
_price = value;
NotifyPropertyChanged("Price");
}
}
private DateTime _date;
public DateTime Date
{
get { return _date; }
set {
_date = value;
NotifyPropertyChanged("Date");
}
}
private string _comment;
public string Comment
{
get { return _comment; }
set
{
_comment = value;
NotifyPropertyChanged("Comment");
}
}
private int _traderId;
public int TraderId
{
get { return _traderId; }
set
{
_traderId = value;
NotifyPropertyChanged("TraderId");
}
}
private Trader _trader;
public Trader Trader
{
get { return _trader; }
set { _trader = value;
TraderData t = new TraderData();
this.Trader = t.Select(value);
}
}
private string _insertType;
/// <summary>
/// A - Auto, M - Manual, V - Verified
/// </summary>
public string InsertType
{
get { return _insertType; }
set { _insertType = value;
NotifyPropertyChanged("InsertType");
}
}
public event PropertyChangedEventHandler PropertyChanged;
// This method is called by the Set accessor of each property.
// The CallerMemberName attribute that is applied to the optional propertyName
// parameter causes the property name of the caller to be substituted as an argument.
//private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
private void NotifyPropertyChanged(String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
项基类
using System.ComponentModel;
namespace PFT.Base
{
public class Item : INotifyPropertyChanged
{
private int _id;
public int Id
{
get { return _id; }
set { _id = value;
NotifyPropertyChanged("Id");
}
}
private string _name;
public string Name
{
get { return _name; }
set { _name = value;
NotifyPropertyChanged("Name");
}
}
private string _description;
public string Description
{
get { return _description; }
set { _description = value;
NotifyPropertyChanged("Description");
}
}
private float _defaultPrice;
public float DefaultPrice
{
get { return _defaultPrice; }
set { _defaultPrice = value;
NotifyPropertyChanged("DefaultPrice");
}
}
private bool _isIncome;
public bool IsIncome
{
get { return _isIncome; }
set { _isIncome = value;
NotifyPropertyChanged("IsIncome");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
使用视图模型执行此操作的方法是为Transaction
提供一个Supplier
属性和一个Item
属性。这些属性将是对实际Item
的引用,并在其自己的集合中Supplier
对象。如果关系是每个事务一个ItemID
和一个SupplierID
,则为对象等效项。如果交易可以是具有相同交易 ID 和不同供应商或物料 ID 的多个记录,则Transaction
需要Item
和Supplier
的集合。我们也可以在 WPF 中执行此操作,但它需要比下面的简单示例更多的尖括号。
当您从数据库中获取项时,您将进行设置(无论您如何执行此操作),或者实体框架可以为您执行此操作。
显示项目名称的真正简单的列表框:添加DisplayMemberPath
。
<ListBox
ItemsSource="{Binding Transactions}"
SelectedItem="{Binding CurrentTransaction}"
DisplayMemberPath="Item.Name"
/>
更复杂的是:
<ListBox
ItemsSource="{Binding Transactions}"
SelectedItem="{Binding CurrentTransaction}"
>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<Run Text="{Binding Item.Name, Mode=OneWay}" />
<Run Text=" - " />
<Run Text="{Binding Supplier.Name, Mode=OneWay}" />
<Run Text=" " />
<Run Text="{Binding Price, Mode=OneWay, StringFormat=c}" />
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
您还可以查看列控件,如ListView
或DataGrid
。
稍微跑题了,零代码隐藏有点极端。这是最后的手段,而不是第三条铁路。最少的代码隐藏是一个合理的一般原则。不要疯狂地试图避免它;它的存在是有原因的。
更新
public class Transaction : INotifyPropertyChanged
{
// ... stuff ...
public Item Item
{
get { return _item; }
set {
_item = value;
// If this property is ever set outside the Transaction
// constructor, you ABSOLUTELY MUST raise PropertyChanged here.
// Otherwise, make the setter private. But just raise the event.
// This has nothing whatsoever to do with when or whether the Item
// class raises PropertyChanged, because this is not a property of the
// Item class. This is a property of Transaction.
NotifyPropertyChanged("Item");
}
}
// ... more stuff ...