|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
using System.Drawing;
|
|
|
|
|
using System.Data;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Windows.Forms;
|
|
|
|
|
using POSV.Entity;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using POSV.Utils;
|
|
|
|
|
using DevComponents.DotNetBar.Metro;
|
|
|
|
|
using DevComponents.DotNetBar;
|
|
|
|
|
|
|
|
|
|
namespace POSV.Component
|
|
|
|
|
{
|
|
|
|
|
[ToolboxItem(true)]
|
|
|
|
|
public partial class ProductXControl : BaseUserControl
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 商品控件默认宽度
|
|
|
|
|
/// </summary>
|
|
|
|
|
public const int PRODUCT_DEFAULT_WIDTH = 104;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 商品控件默认高度
|
|
|
|
|
/// </summary>
|
|
|
|
|
public const int PRODUCT_DEFAULT_HEIGHT = 76;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 数据源
|
|
|
|
|
/// </summary>
|
|
|
|
|
private List<ProductExt> _dataSource = null;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 显示价格类型
|
|
|
|
|
/// </summary>
|
|
|
|
|
private PriceTypeEnum _priceType = PriceTypeEnum.零售价;
|
|
|
|
|
|
|
|
|
|
//这样可以加快多次创建item速度,否则每次要耗时2毫秒
|
|
|
|
|
private Image _defaultImage = global::POSV.Properties.Resources.圆角矩形_2x;
|
|
|
|
|
|
|
|
|
|
public ProductXControl()
|
|
|
|
|
{
|
|
|
|
|
InitializeComponent();
|
|
|
|
|
|
|
|
|
|
this.itemPanel.ResizeItemsToFit = false;
|
|
|
|
|
this.itemPanel.BackgroundStyle.Class = "MetroTileGroupTitle";//很关键
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void OnLoad(EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
base.OnLoad(e);
|
|
|
|
|
|
|
|
|
|
if (this.DesignMode) return;
|
|
|
|
|
|
|
|
|
|
ReCalSize();
|
|
|
|
|
|
|
|
|
|
this.Resize += OnResize;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnResize(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
switch (this.FindForm().WindowState)
|
|
|
|
|
{
|
|
|
|
|
case FormWindowState.Normal:
|
|
|
|
|
case FormWindowState.Maximized:
|
|
|
|
|
{
|
|
|
|
|
ReCalSize();
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ReCalSize()
|
|
|
|
|
{
|
|
|
|
|
//计算能显示的列数
|
|
|
|
|
var _width = this.ItemWidth + this.ItemSpace - 1;
|
|
|
|
|
if (_width != 0)
|
|
|
|
|
{
|
|
|
|
|
this.Columns = ((this.Width - this.Padding.Left - this.Padding.Right) / _width);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//根据行数,重新规划高度
|
|
|
|
|
var _height = this.ItemHeight + this.ItemSpace - 1;
|
|
|
|
|
if (_height != 0)
|
|
|
|
|
{
|
|
|
|
|
this.Rows = ((this.Height - this.Padding.Top - this.Padding.Bottom) / _height);
|
|
|
|
|
}
|
|
|
|
|
this.ItemHeight = (this.Height - this.Padding.Top - this.Padding.Bottom) / this.Rows - this.ItemSpace;
|
|
|
|
|
|
|
|
|
|
BindDataSource(this._dataSource, this._priceType);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void BindDataSource(List<ProductExt> dataSource, PriceTypeEnum priceType)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (dataSource == null)
|
|
|
|
|
{
|
|
|
|
|
this._dataSource = new List<ProductExt>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//加入分页,避免污染源数据,新建集合
|
|
|
|
|
List<ProductExt> list = new List<ProductExt>();
|
|
|
|
|
list.AddRange(dataSource);
|
|
|
|
|
this._dataSource = list;
|
|
|
|
|
|
|
|
|
|
this._priceType = priceType;
|
|
|
|
|
|
|
|
|
|
//可以考虑更优化的分摊机制?张莹
|
|
|
|
|
int deltaX = this.Width - this.Padding.Left - this.Padding.Right - (this.ItemWidth + this.ItemSpace) * this.Columns - this.ItemSpace;
|
|
|
|
|
int deltaY = this.Height - this.Padding.Top - this.Padding.Bottom - (this.ItemHeight + this.ItemSpace) * this.Rows - this.ItemSpace;
|
|
|
|
|
|
|
|
|
|
this.TotalCount = this._dataSource.Count;
|
|
|
|
|
this.PageSize = this.Columns * this.Rows;
|
|
|
|
|
//清空历史数据
|
|
|
|
|
this.itemPanel.Items.Clear();
|
|
|
|
|
|
|
|
|
|
//复制新的数据源,进行分页运算
|
|
|
|
|
var merge = ProductXMerge.Merge(this.Rows, this.Columns, this._dataSource, false);
|
|
|
|
|
var pager = ListPager(merge);
|
|
|
|
|
|
|
|
|
|
ItemContainer mainContainer = new ItemContainer();
|
|
|
|
|
mainContainer.Name = "productContainer";
|
|
|
|
|
mainContainer.MultiLine = (this.Rows > 1);
|
|
|
|
|
mainContainer.ItemSpacing = this.ItemSpace;
|
|
|
|
|
mainContainer.LayoutOrientation = eOrientation.Horizontal;
|
|
|
|
|
|
|
|
|
|
for (int i=0;i < pager.Count;i++)
|
|
|
|
|
{
|
|
|
|
|
ProductExt entity = pager[i];
|
|
|
|
|
|
|
|
|
|
MetroTileItem item = new MetroTileItem();
|
|
|
|
|
item.TileStyle.PaddingLeft = item.TileStyle.PaddingRight = 0;
|
|
|
|
|
item.EnableMarkup = true;
|
|
|
|
|
item.OptionGroup = "product";
|
|
|
|
|
item.TileStyle.BorderWidth = 0;
|
|
|
|
|
item.TileStyle.BackColor = Color.Transparent;
|
|
|
|
|
item.TileStyle.BackColor2 = Color.Transparent;
|
|
|
|
|
item.TileStyle.BorderColor = Color.Transparent;
|
|
|
|
|
item.TileStyle.BorderColor2 = Color.Transparent;
|
|
|
|
|
|
|
|
|
|
//判断商品背景
|
|
|
|
|
item.TileStyle.BackgroundImage = _defaultImage;
|
|
|
|
|
|
|
|
|
|
item.TileStyle.BackgroundImagePosition = eStyleBackgroundImage.Stretch;
|
|
|
|
|
item.TitleTextAlignment = ContentAlignment.MiddleCenter;
|
|
|
|
|
item.Checked = false;
|
|
|
|
|
//将宽度进行补偿
|
|
|
|
|
int _width = this.ItemWidth + (this.Columns > 0 ? (deltaX / this.Columns) : 0);
|
|
|
|
|
|
|
|
|
|
int _offsetWidth = this.Columns > 0 ? (deltaX % this.Columns) : 0;
|
|
|
|
|
|
|
|
|
|
//if (i % _offsetWidth == 0)
|
|
|
|
|
//{
|
|
|
|
|
// _width += _offset;
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
//将高度误差补入第一行
|
|
|
|
|
int _height = this.ItemHeight + deltaY;
|
|
|
|
|
//if (this.Columns - mainContainer.SubItems.Count > 0)
|
|
|
|
|
//{
|
|
|
|
|
// _height += deltaY;
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
//显示大小
|
|
|
|
|
item.TileSize = new Size(_width, _height);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//显示编码后,调整呈现位置
|
|
|
|
|
item.TileStyle.TextAlignment = DevComponents.DotNetBar.eStyleTextAlignment.Center;
|
|
|
|
|
item.TileStyle.TextLineAlignment = DevComponents.DotNetBar.eStyleTextAlignment.Near;
|
|
|
|
|
item.TitleTextAlignment = System.Drawing.ContentAlignment.BottomRight;
|
|
|
|
|
var price = decimal.Zero;
|
|
|
|
|
switch (this._priceType)
|
|
|
|
|
{
|
|
|
|
|
case PriceTypeEnum.零售价:
|
|
|
|
|
{
|
|
|
|
|
price = entity.Price;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case PriceTypeEnum.最低售价:
|
|
|
|
|
{
|
|
|
|
|
price = entity.MinPrice;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case PriceTypeEnum.外送价:
|
|
|
|
|
{
|
|
|
|
|
price = entity.OtherPrice;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case PriceTypeEnum.会员价:
|
|
|
|
|
{
|
|
|
|
|
price = entity.MemberPrice;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
//品名
|
|
|
|
|
item.TileStyle.TextColor = ColorTranslator.FromHtml("#444444");
|
|
|
|
|
//售价
|
|
|
|
|
item.TitleTextColor = ColorTranslator.FromHtml("#F45B63");
|
|
|
|
|
|
|
|
|
|
//绑定商品Tag属性
|
|
|
|
|
item.Tag = ObjectUtils.Copy(entity);
|
|
|
|
|
switch (entity.Name)
|
|
|
|
|
{
|
|
|
|
|
case Constant.PREV_PAGER:
|
|
|
|
|
{
|
|
|
|
|
item.TileStyle.BackgroundImage = _defaultImage;
|
|
|
|
|
item.Image = global::POSV.Properties.Resources.上一页_2x;
|
|
|
|
|
item.ImageTextAlignment = ContentAlignment.MiddleCenter;
|
|
|
|
|
item.Text = string.Empty;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case Constant.NEXT_PAGER:
|
|
|
|
|
{
|
|
|
|
|
item.TileStyle.BackgroundImage = _defaultImage;
|
|
|
|
|
item.Image = global::POSV.Properties.Resources.下一页_2x;
|
|
|
|
|
item.ImageTextAlignment = ContentAlignment.MiddleCenter;
|
|
|
|
|
item.Text = string.Empty;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
{
|
|
|
|
|
//显示编码后,调整呈现位置
|
|
|
|
|
item.TitleText = string.Format("¥{0}", price.ToString());
|
|
|
|
|
|
|
|
|
|
//绑定商品名称到Text属性
|
|
|
|
|
item.Text = entity.Name;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
item.MouseDown -= OnProductMouseDown;
|
|
|
|
|
item.MouseDown += OnProductMouseDown;
|
|
|
|
|
|
|
|
|
|
mainContainer.SubItems.Add(item);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.itemPanel.Items.Insert(0, mainContainer);
|
|
|
|
|
|
|
|
|
|
this.itemPanel.Invalidate();
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
LOGGER.Error(ex, "构建商品控件内容异常");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnProductMouseDown(object sender, MouseEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (e.Button == MouseButtons.Left)
|
|
|
|
|
{
|
|
|
|
|
MetroTileItem item = (MetroTileItem)sender;
|
|
|
|
|
|
|
|
|
|
var product = item.Tag as ProductExt;
|
|
|
|
|
|
|
|
|
|
switch (product.Name)
|
|
|
|
|
{
|
|
|
|
|
case Constant.PREV_PAGER:
|
|
|
|
|
{
|
|
|
|
|
this.PageNumber = product.Pager;
|
|
|
|
|
this.BindDataSource(this._dataSource, this._priceType);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case Constant.NEXT_PAGER:
|
|
|
|
|
{
|
|
|
|
|
this.PageNumber = product.Pager;
|
|
|
|
|
this.BindDataSource(this._dataSource, this._priceType);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
{
|
|
|
|
|
OnProductXClick(new ProductXEventArgs((ProductExt)item.Tag));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public event ProductXEventHandler ProductXClick;
|
|
|
|
|
protected virtual void OnProductXClick(ProductXEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
ProductXClick?.Invoke(this, e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 分页List数据
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public List<T> ListPager<T>(List<T> data)
|
|
|
|
|
{
|
|
|
|
|
var result = new List<T>();
|
|
|
|
|
|
|
|
|
|
result.AddRange(data.Skip((this.PageNumber - 1) * this.PageSize).Take(this.PageSize));
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private MetroTileItem _selectedItem = null;
|
|
|
|
|
|
|
|
|
|
public MetroTileItem SelectedItem
|
|
|
|
|
{
|
|
|
|
|
get { return this._selectedItem; }
|
|
|
|
|
private set { this._selectedItem = value; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 每页数量
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int PageSize { get; private set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 总页数
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int PageCount => this.PageSize <= 0 ? 0 : ((TotalCount + this.PageSize - 1) / this.PageSize);
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 当前页码
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int PageNumber { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 总数量
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int TotalCount { get; private set; }
|
|
|
|
|
|
|
|
|
|
private int _columns = 1;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 显示的列数
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int Columns
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return _columns;
|
|
|
|
|
}
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_columns = (value < 0 ? 1 : value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private int _rows = 1;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 显示行数
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int Rows
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return _rows;
|
|
|
|
|
}
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_rows = (value < 0 ? 1 : value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int ItemHeight { get; set; } = PRODUCT_DEFAULT_HEIGHT;
|
|
|
|
|
|
|
|
|
|
public int ItemWidth { get; set; } = PRODUCT_DEFAULT_WIDTH;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 控件间距
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int ItemSpace { get; set; } = 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 价格类型
|
|
|
|
|
/// </summary>
|
|
|
|
|
public enum PriceTypeEnum
|
|
|
|
|
{
|
|
|
|
|
零售价,
|
|
|
|
|
会员价,
|
|
|
|
|
进价,
|
|
|
|
|
最低售价,
|
|
|
|
|
配送价,
|
|
|
|
|
批发价,
|
|
|
|
|
外送价
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public delegate void ProductXEventHandler(object sender, ProductXEventArgs e);
|
|
|
|
|
|
|
|
|
|
public class ProductXEventArgs : EventArgs
|
|
|
|
|
{
|
|
|
|
|
public ProductExt Product;
|
|
|
|
|
public ProductXEventArgs(ProductExt data)
|
|
|
|
|
{
|
|
|
|
|
this.Product = data;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class ProductXMerge
|
|
|
|
|
{
|
|
|
|
|
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
|
|
|
|
|
|
|
|
|
|
public static List<ProductExt> Merge(int rows, int cols, List<ProductExt> dataSource, bool touchEnabled)
|
|
|
|
|
{
|
|
|
|
|
Stopwatch sw = Stopwatch.StartNew();
|
|
|
|
|
|
|
|
|
|
//启用触摸屏,不分页
|
|
|
|
|
if (touchEnabled)
|
|
|
|
|
{
|
|
|
|
|
return dataSource;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//移除可能存在的分页标识
|
|
|
|
|
dataSource.RemoveAll(x => Constant.PREV_PAGER.Equals(x.Name) || Constant.NEXT_PAGER.Equals(x.Name));
|
|
|
|
|
|
|
|
|
|
int pageSize = rows * cols;
|
|
|
|
|
|
|
|
|
|
int totalCount = dataSource.Count;
|
|
|
|
|
|
|
|
|
|
//启用分页
|
|
|
|
|
int pageCount = ((totalCount - 1) + (pageSize - 2) - 1) / (pageSize - 2);
|
|
|
|
|
|
|
|
|
|
if (pageCount > 1)
|
|
|
|
|
{
|
|
|
|
|
int offset = 0;
|
|
|
|
|
for (int page = 1; page <= pageCount; page++)
|
|
|
|
|
{
|
|
|
|
|
if (page == 1)
|
|
|
|
|
{
|
|
|
|
|
offset = page * pageSize - 1;
|
|
|
|
|
|
|
|
|
|
var entity = new ProductExt();
|
|
|
|
|
entity.Id = IdWorkerUtils.Instance.NextId();
|
|
|
|
|
entity.Name = Constant.NEXT_PAGER;
|
|
|
|
|
entity.Pager = (page + 1);
|
|
|
|
|
|
|
|
|
|
dataSource.Insert(offset, entity);
|
|
|
|
|
}
|
|
|
|
|
else if (page < pageCount)
|
|
|
|
|
{
|
|
|
|
|
offset = page * pageSize - 2;
|
|
|
|
|
|
|
|
|
|
var entity = new ProductExt();
|
|
|
|
|
entity.Id = IdWorkerUtils.Instance.NextId();
|
|
|
|
|
entity.Name = Constant.PREV_PAGER;
|
|
|
|
|
entity.Pager = (page - 1);
|
|
|
|
|
|
|
|
|
|
dataSource.Insert(offset, entity);
|
|
|
|
|
|
|
|
|
|
offset++;
|
|
|
|
|
|
|
|
|
|
entity = new ProductExt();
|
|
|
|
|
entity.Id = IdWorkerUtils.Instance.NextId();
|
|
|
|
|
entity.Name = Constant.NEXT_PAGER;
|
|
|
|
|
entity.Pager = (page + 1);
|
|
|
|
|
|
|
|
|
|
dataSource.Insert(offset, entity);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
var entity = new ProductExt();
|
|
|
|
|
entity.Id = IdWorkerUtils.Instance.NextId();
|
|
|
|
|
entity.Name = Constant.PREV_PAGER;
|
|
|
|
|
entity.Pager = (page - 1);
|
|
|
|
|
|
|
|
|
|
dataSource.Add(entity);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
logger.Info("商品控件插入分页控件,耗时<{0}>", sw.ElapsedMilliseconds);
|
|
|
|
|
return dataSource;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|