购物 - 适用于 Pocket PC 的 .NET 购物应用程序






4.14/5 (20投票s)
Shopping 是一个用 C# 为 Pocket PC 编写的应用程序。它是一个可以帮助您满足日常购物需求的程序。
引言
作为一名软件开发人员,并且首先是一名技术宅,我梦想着通过用数字化的对应物取代纸和笔,让它们变得毫无用处。显然,我们离这个梦想还很远。然而,随着 Pocket PC,特别是 Pocket Framework 的出现,我发现了一个实现这个梦想的强大工具。
在我为 Code Project 比赛寻找完美项目时,我偶然发现了我女朋友每周都会用的一张小纸片,上面是她的购物清单。太棒了!我找到了我的项目,也找到了让铅笔和纸变得毫无用处的方法。我要为购物计划构建一个 Pocket PC 应用程序!
本文作为一份高度精简的分析文档而撰写。您将找到有关需求、用户界面指南、系统设计的信息,最后是一个部分,您将找到有关代码中最有趣部分的实现细节。
术语
在购物应用程序讨论中,始终使用以下术语
- 购物车:表示一个购物车商品列表。这是一个购物清单,是用于购物计划的一张纸的数字化对应物。
- 购物车商品:表示购物车中的特定商品,每个商品都是您想要购买的产品。
- 产品:产品是一个购物车商品。
背景 - 用户需求
购物应用程序的主要挑战并非代码部分,而是设计部分。显然,目标是构建一个有趣的应用程序,但首先,它必须是一个真正可以融入日常生活的有用应用程序。
应用程序的需求可以总结为:
- 用户直观:人们不看帮助文件!我认为任何与客户打交道的专业开发人员都会证实,人们不看帮助文件。应用程序应该直观且用户友好,否则人们就不会使用它。
- 用户应尽可能对事物进行分类,以便筛选信息。
- 用户应能够定义产品以进行快速输入。
- 用户应能够定义产品的单位。每个产品应提供一个默认单位,默认为空。
- 用户输入应保持在最低限度。
- 使用应用程序应优于使用纸张:如果用户从使用购物应用程序中没有获得好处,他就会放弃它。
购物应用程序 - 用户界面指南
当购物应用程序打开时,它会显示一个现有购物车列表。第一次打开时,您会看到一个空白屏幕。可用购物车列表可以过滤,以显示符合特定条件的购物车,这些条件基于购物车所属的类别。
要添加新购物车,请单击新建图标,或在列表中选择一个现有购物车,然后单击克隆图标,将选定的购物车用作新购物车的模板。打开现有购物车可以通过双击列表中的购物车,或在列表中选择一个购物车并单击打开图标来实现。
图 1 显示了具有符合当前过滤器(类别 = 杂货)的几个购物车的初始屏幕。
图 1:购物应用程序的启动屏幕。
产品定义
图 2 显示了产品定义屏幕。用户在此处定义创建新购物车所需的产品。您可以通过单击选项按钮,然后选择管理/产品编辑器菜单来访问产品定义屏幕。要添加新产品,请单击新建按钮并在文本框中输入产品名称。您可以选择为每个产品指定一个默认单位。单击添加按钮添加产品。窗口关闭时,更改会自动保存。
图 2:产品定义屏幕。
单位定义
图 3 显示了单位定义屏幕。用户在此处定义产品的单位。您可以通过单击选项按钮,然后选择管理/单位编辑器菜单来访问单位定义屏幕。要添加新单位,请单击新建按钮并在文本框中输入单位名称。单击添加按钮添加单位。窗口关闭时,更改会自动保存。
图 3:单位定义屏幕。
使用购物车屏幕
购物车屏幕是纸质购物清单的数字对应物。此屏幕显示购物清单项目,包含以下信息:产品名称、数量、格式和通知图标(如果条目关联了备注,产品名称旁边会有一个备注图标)。购物车的标题和类别可以在“属性”选项卡上更改。
加号和X图标用于在列表中添加和删除项目。项目也可以通过向上和向下箭头图标在列表中上下移动。最后一个图标用于切换操作模式,从购物模式切换到编辑模式。在购物模式下,可以通过用触控笔点击项目来将其设置为已选中。在购物模式下,无法添加或删除项目。
窗口关闭时,更改会自动保存。
图 4:购物车屏幕。
商品编辑器
当您在“购物车”屏幕中点击加号图标,或者双击现有商品时,此屏幕就会显示。要向列表中添加新商品,请从列表中选择一个产品,指定数量,并可选择更改商品的单位(如果它不正确)。
通过使用切换类别按钮,可以轻松过滤产品列表。当您点击一个切换类别(例如 Mno)时,只会显示以字母“m”或更大字母开头的商品。重复点击一个已切换的类别会交替显示类别的字母(Mno, mNo, mnO, Mno ...)。
备注选项卡包含一个文本区域,用于为商品添加备注。如前所述,当商品附加备注时,商品名称旁边会显示一个图标。
更改通过保存(绿色)按钮保存,而取消(红色)按钮用于取消更改。
图 5:商品编辑器屏幕。
设计与实现
设计遵循两层架构(用户界面、业务逻辑)。数据层已包含在业务规则中以简化。项目已分为三个程序集:
- Shopping.GUI:这是可执行文件。所有表单都可以在这里找到。
- McSoft.UILib:Shopping 程序集使用的所有用户控件都位于此处。
- Shopping.Engine:这是业务规则。
应用程序的设计相当简单。业务规则仅包含六个公共类。
ShoppingApp
:此类是应用程序的抽象。此类包含多种管理购物车的方法,例如:创建、删除、打开和克隆。Product
:此类主要由产品编辑器屏幕使用,它代表一个产品。此类提供一个序列化方法,封装了产品列表的 XML 序列化。Cart
:此类是购物清单的抽象。它包含一个CartItem
集合,并提供一个序列化方法,封装了Cart
的 XML 序列化。CartItem
:此类是Cart
中一个项目的抽象。它提供一个序列化方法,封装了单个项目的XML序列化。ProductsComparer
:此类用于ArrayList
的自定义排序。更多信息请参阅:使用IComparer
在ArrayList
上实现自定义排序 部分。CST
:这是一个实用程序类,您只会在其中找到其他程序集使用的公共常量。
用户控件和双缓冲
在编写购物应用程序期间,Compact Framework 出现了一些问题。然而,最明显的问题是可用用户控件在功能和多样性方面非常有限。例如,Button
控件没有 picture
属性,这很可惜。因此,我决定亲自动手编写自己的控件。
我为这个项目编写了 9 个用户控件和 2 个支持类。我不会详细介绍每个控件,但我会指出一些编写 Compact Framework 控件最有用的技巧。
- 对于您编写的每个控件,请覆盖
OnClick
方法,并确保存在以下代码protected override void OnClick(EventArgs e) { this.Focus(); base.OnClick(e); }
如果您忘记这样做,点击您的控件将不会使其获得焦点。副作用是您的其他控件将不会收到
LostFocus
事件。在我的例子中,我通过创建一个抽象类,继承自Control
(参见McSoftControl
)来解决这个问题。我的所有控件都继承自这个类,所以我不必担心这个问题。如果您为任何派生控件覆盖OnClick
,请不要忘记调用base.OnClick()
。 - 如果您编写自己的控件,您会发现的第一件事是,要制作出花哨酷炫的控件,您绝对需要了解如何覆盖
OnPaint
事件并自定义绘制您的控件。我不会深入探讨如何使用Graphics
类。但是,我想特别指出的是,如果您想做得干净利落,您需要使用双缓冲来消除闪烁。双缓冲是一种技术,您将控件渲染到内存中的图像缓冲区中,然后使用缓冲区的内容更新实际控件的显示。以下代码片段演示了您可以在
CartView
类中找到的该技术。protected override void OnPaint(PaintEventArgs e) { Bitmap offScreen = new Bitmap(this.ClientSize.Width, this.ClientSize.Height); Graphics gOffScreen = Graphics.FromImage(offScreen); // ... Do your drawing here by using the gOffScreen instance. e.Graphics.DrawImage(offScreen, 0, 0, this.ClientRectangle, GraphicsUnit.Pixel); gOffScreen.Dispose(); }
此外,当以这种方式使用双缓冲时,不要忘记覆盖
OnPaintBackground
,但没有任何实现,如下所示:protected override void OnPaintBackground(PaintEventArgs e) { // DO NOT REMOVE THIS METHOD OR FLICKERING WILL OCCURS }
使用 IComparer 在 ArrayList 上实现自定义排序
我最喜欢的 .NET 框架类之一是 SortedList
集合。不幸的是,Compact Framework 中不存在此类。我最初的打算是使用 SortedList
集合来添加可用产品,以便根据它们的名称进行排序。经过快速研究,我发现,可以使用 ArrayList
集合和基于 IComparer
的自定义比较器来实现相同的功能。
在我的例子中,我创建了一个名为 ProductsComparer
的自定义比较器,它比较两个 Product
对象实例的 name
属性。以下是 ProductsComparer
类的完整实现:
public class ProductsComparer : IComparer
{
int IComparer.Compare(Object x, Object y)
{
return( (Product)x).Name.CompareTo( ((Product)y).Name);
}
}
以下是我使用此类别根据其 name
属性对 Product
实例的 ArrayList
进行排序的地方
// Note: mProducts is an ArrayList
IComparer myComparer = new ProductsComparer();
mProducts.Sort(myComparer);
实现 OnDoubleClick 事件
在 Compact Framework 中不要寻找 OnDoubleClick
事件,因为它不存在。我曾想在我的列表上覆盖 OnDoubleClick
事件,以便当用户双击列表中的购物车时可以打开购物车。幸运的是,这个事件可以通过 OnClick
事件轻松模拟。以下是我在 OwnerDrawnListView
类(CartsView
和 CartView
的基类)中实现它的方式:
namespace McSoft.UILib
{
public delegate void DoubleClickEventHandler(object sender, EventArgs e);
public abstract class OwnerDrawnListView : McSoftControl
{
// Partial class implementation to demonstrate
// OnDoubleClick event, see class
// OwnerDrawnListView for full implementation
public event DoubleClickEventHandler OnDoubleClick;
private int previousClick = SystemInformation.DoubleClickTime + 1;
protected override OnClick(EventArgs e)
{
int now = System.Environment.TickCount;
if(now - previousClick <= System.information.DoubleClickTime)
if(OnDoubleClick != null) OnDoubleClick(this.selectedIndex, e);
previousClick = now;
base.onClick (e);
}
}
}
历史
这是应用程序的 1.0 版本。
路线图
- 给产品添加价格。
- 为产品添加类别。
- 清理代码以将产品、单位和类别编辑器合并在一起。
- 使用更强大的过滤器更新购物车过滤功能。
- 添加一个选项页面,用户可以在其中更改应用程序颜色、删除确认等...