如何在 WPF 视图模型中使用关系表



我正在构建一个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需要ItemSupplier的集合。我们也可以在 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>

您还可以查看列控件,如ListViewDataGrid

稍微跑题了,零代码隐藏有点极端。这是最后的手段,而不是第三条铁路。最少的代码隐藏是一个合理的一般原则。不要疯狂地试图避免它;它的存在是有原因的。

更新

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 ...

最新更新