RaUI/Source/ryControls/Sheng.Winform.Controls/ShengListView/ShengListView.cs
鑫Intel c3d4ddf574 ### 2021-07-29更新
------
#### MyDbV4   V3.0.2107.2901
- *.[新增]新增支持计算文件MD5。
- *.[新增]部分DataProvider功能移植到DbExtension里,增加扩展性。
- *.[新增]UnixTimeToDateTime和JSTimeToDateTime新增支持long参数。
- *.[合并]合并RyWeb项目到MyDb里。

#### ryControlsV4    V3.0.2107.2901
  -  *.[改进]优化减少大量IDE警告和消息。
2021-07-29 17:09:32 +08:00

955 lines
26 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
using System.Drawing;
using System.Diagnostics;
using System.Reflection;
using Sheng.Winform.Controls.Kernal;
using System.Collections;
namespace Sheng.Winform.Controls
{
/// <summary>
///
/// </summary>
public class ShengListView : Control
{
#region
/// <summary>
/// Creates a control with a border.
/// </summary>
private const int WS_BORDER = 0x00800000;
/// <summary>
/// Specifies that the control has a border with a sunken edge.
/// </summary>
private const int WS_EX_CLIENTEDGE = 0x00000200;
#endregion
#region
private bool _suspendLayout = false;
/// <summary>
///
/// </summary>
public bool Suspend
{
get { return _suspendLayout; }
}
/// <summary>
/// 是否需要在调用 ResumeLayout 时重绘
/// </summary>
private bool _needPaint = false;
private ShengListViewLayoutManager _layoutManager;
/// <summary>
/// 为项扩展的用于呈现的属性
/// </summary>
private readonly Dictionary<string, string> _extendMember = new Dictionary<string, string>();
//ToolTip _toolTip = new ToolTip();
//private System.Timers.Timer lazyRefreshTimer;
#endregion
#region
/// <summary>
/// Gets whether the shift key is down.
/// </summary>
internal bool ShiftKey { get; private set; }
/// <summary>
/// Gets whether the control key is down.
/// </summary>
internal bool ControlKey { get; private set; }
/// <summary>
/// 鼠标左键是否处于按下状态
/// </summary>
internal bool LeftButton { get; private set; }
/// <summary>
/// 鼠标右键是否处于按下状态
/// </summary>
internal bool RightButton { get; private set; }
internal bool AnyMouseButton
{
get { return LeftButton || RightButton; }
}
//debug public
/// <summary>
/// 鼠标最后点击的位置
/// </summary>
internal Point LastMouseDownLocation { get; private set; }
private ShengListViewItem _hoveredItem;
/// <summary>
/// 当前鼠标经过的项
/// </summary>
internal ShengListViewItem HoveredItem
{
get { return _hoveredItem; }
private set
{
ShengListViewItem oldHoveredItem = _hoveredItem;
ShengListViewItem newHoveredItem = value;
_hoveredItem = value;
if (oldHoveredItem != null && oldHoveredItem != newHoveredItem)
{
oldHoveredItem.Hovered = false;
}
if (newHoveredItem != null)
newHoveredItem.Hovered = true;
if (oldHoveredItem != newHoveredItem)
{
NeedPaint();
}
}
}
private ShengListViewLayoutMode _layoutMode;
/// <summary>
///
/// </summary>
public ShengListViewLayoutMode LayoutMode
{
get { return _layoutMode; }
set
{
_layoutMode = value;
ShengListViewLayoutManager layoutManager;
switch (_layoutMode)
{
case ShengListViewLayoutMode.Standard:
layoutManager = new ShengListViewStandardLayoutManager(this);
break;
case ShengListViewLayoutMode.Descriptive:
layoutManager = new ShengListViewDescriptiveLayoutManager(this);
break;
default:
layoutManager = new ShengListViewLayoutManager(this);
Debug.Assert(false, "没这ListViewRenderer");
break;
}
SetLayoutManager(layoutManager);
}
}
private BorderStyle _borderStyle = BorderStyle.Fixed3D;
/// <summary>
///
/// </summary>
public BorderStyle BorderStyle
{
get { return _borderStyle; }
set { _borderStyle = value; }
}
private ShengListViewTheme _theme = new ShengListViewTheme();
/// <summary>
/// 配色方案
/// </summary>
public ShengListViewTheme Theme
{
get
{
return _theme;
}
set
{
_theme = value;
Refresh();
}
}
/// <summary>
/// 当前布局中项的高度
/// </summary>
public int ItemHeight
{
get { return _layoutManager.ItemHeightWithMargin; }
}
private bool _allowMultiSelection = false;
/// <summary>
///
/// </summary>
public bool AllowMultiSelection
{
get { return _allowMultiSelection; }
set { _allowMultiSelection = value; }
}
/// <summary>
/// 是否没有任何项
/// </summary>
public bool IsEmpty
{
get
{
return Items.Count == 0;
}
}
private ShengListViewItemCollection _items = new ShengListViewItemCollection();
/// <summary>
///
/// </summary>
public ShengListViewItemCollection Items
{
get { return _items; }
set { _items = value; }
}
/// <summary>
/// 获取当前具有输入焦点的项
/// </summary>
public ShengListViewItem FocusedItem
{
get
{
foreach (var item in _items)
{
if (item.Focused)
return item;
}
return null;
}
}
/// <summary>
/// 默认的用于呈现为项中文本的Property
/// </summary>
public string DisplayMember
{
get;
set;
}
#endregion
#region
/// <summary>
///
/// </summary>
public ShengListView()
{
SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
SetStyle(ControlStyles.Selectable, true);
this.Padding = new System.Windows.Forms.Padding(10);
_items.Owner = this;
//设置一个默认布局
this.LayoutMode = ShengListViewLayoutMode.Standard;
//_layoutManager = new ListViewLayoutManager(this);
//lazyRefreshTimer = new System.Timers.Timer();
//lazyRefreshTimer.Interval = 10;
//lazyRefreshTimer.Enabled = false;
//lazyRefreshTimer.Elapsed += lazyRefreshTimer_Tick;
//lazyRefreshCallback = new RefreshDelegateInternal(Refresh);
}
//delegate void RefreshDelegateInternal();
//private RefreshDelegateInternal lazyRefreshCallback;
//void lazyRefreshTimer_Tick(object sender, EventArgs e)
//{
// if (IsHandleCreated && IsDisposed == false)
// BeginInvoke(lazyRefreshCallback);
// lazyRefreshTimer.Stop();
//}
#endregion
#region
#region internal
/// <summary>
/// 更改了选择的项
/// </summary>
internal void OnSelectedItemChanged()
{
SelectedItemChanaged?.Invoke(this, new EventArgs());
}
/// <summary>
/// 双击项
/// </summary>
/// <param name="item"></param>
internal void OnItemDoubleClick(ShengListViewItem item)
{
ItemDoubleClick?.Invoke(this, new ShengListViewItemDoubleClickEventArgs(item));
}
internal void OnItemsRemoved(List<ShengListViewItem> items)
{
_layoutManager.OnItemsRemoved(items);
ItemsRemoved?.Invoke(this, new ShengListViewItemsRemovedEventArgs(items));
}
/// <summary>
/// 请求在下次调用 ResumeLayout 时重绘
/// </summary>
internal void NeedPaint()
{
_needPaint = true;
}
internal void RenderItem(ShengListViewItem item)
{
if (Suspend == false)
{
_layoutManager.RenderItem(this.CreateGraphics(), item);
}
}
internal object GetItemPropertyValue(object itemValue, string propertyName)
{
if (itemValue == null || String.IsNullOrEmpty(propertyName))
{
Debug.Assert(false, "itemValue 或 propertyName 为空");
throw new ArgumentNullException();
}
return ReflectionPool.GetPropertyValue(itemValue, propertyName);
}
internal string GetItemText(object itemValue)
{
Debug.Assert(itemValue != null, "itemValue 为 null");
if (itemValue == null)
return String.Empty;
if (ItemTextGetting != null)
{
ShengListViewGetItemTextEventArgs args = new ShengListViewGetItemTextEventArgs(itemValue);
ItemTextGetting(this, args);
if (String.IsNullOrEmpty(args.Text) == false)
return args.Text;
}
if (String.IsNullOrEmpty(DisplayMember))
{
return itemValue.ToString();
}
else
{
return GetItemText(itemValue, DisplayMember);
}
}
internal string GetItemText(object itemValue, string propertyName)
{
Debug.Assert(itemValue != null && String.IsNullOrEmpty(propertyName) == false, "itemValue 为 null");
object text = GetItemPropertyValue(itemValue, propertyName);
if (text == null)
return String.Empty;
else
return text.ToString();
}
/// <summary>
/// 获取当前选中的所有项
/// </summary>
/// <returns></returns>
internal List<ShengListViewItem> GetSelectedItems()
{
List<ShengListViewItem> items = new List<ShengListViewItem>();
foreach (var item in _items)
{
if (item.Selected)
items.Add(item);
}
return items;
}
#endregion
#region public
/// <summary>
///
/// </summary>
/// <param name="member"></param>
public void AddExtendMember(IShengListViewExtendMember member)
{
Dictionary<string, string> extendMembers = member.GetExtendMembers();
foreach (var item in extendMembers)
{
SetExtendMember(item.Key, item.Value);
}
}
/// <summary>
/// 设置扩展属性供特定LayoutEngine使用
/// 如果指定的 ExtendMember 已存在,覆盖之
/// 用String.Empty 或 null 做为 propertyName传入表示删除指定的 member
/// </summary>
/// <param name="member"></param>
/// <param name="propertyName"></param>
public void SetExtendMember(string member, string propertyName)
{
if (String.IsNullOrEmpty(member))
{
Debug.Assert(false, "member 为空");
throw new ArgumentNullException();
}
if (String.IsNullOrEmpty(propertyName))
{
_extendMember.Remove(member);
}
else
{
if (_extendMember.Keys.Contains(member))
{
_extendMember[member] = propertyName;
}
else
{
_extendMember.Add(member, propertyName);
}
}
}
/// <summary>
///
/// </summary>
/// <param name="member"></param>
/// <returns></returns>
public bool ContainerExtendMember(string member)
{
if (String.IsNullOrEmpty(member) )
{
Debug.Assert(false, "member 为空");
throw new ArgumentNullException();
}
return _extendMember.Keys.Contains(member);
}
/// <summary>
///
/// </summary>
/// <param name="member"></param>
/// <returns></returns>
public string GetExtendMember(string member)
{
if (ContainerExtendMember(member) == false)
{
Debug.Assert(false, "指定的 member 不存在" + member);
throw new ArgumentOutOfRangeException();
}
return _extendMember[member];
}
/// <summary>
/// 恢复正常的布局逻辑。
/// </summary>
public new void ResumeLayout()
{
_suspendLayout = false;
if (_needPaint)
{
this.Refresh();
_needPaint = false;
}
base.ResumeLayout();
}
/// <summary>
///
/// </summary>
/// <param name="refreshNow"></param>
public new void ResumeLayout(bool refreshNow)
{
_suspendLayout = false;
if (refreshNow)
{
this.Refresh();
_needPaint = false;
}
else
{
ResumeLayout();
}
base.ResumeLayout(refreshNow);
}
/// <summary>
/// 临时挂起控件的布局逻辑。
/// </summary>
public new void SuspendLayout()
{
_suspendLayout = true;
base.SuspendLayout();
}
/// <summary>
///
/// </summary>
public override void Refresh()
{
if (_suspendLayout)
return;
base.Refresh();
}
/// <summary>
/// 获取当前选中项所绑定的对象
/// 如果没有选中项返回null如果选中多项返回选中项集合中的第一个
/// </summary>
/// <returns></returns>
public object GetSelectedValue()
{
List<ShengListViewItem> selectedItems = GetSelectedItems();
if (selectedItems.Count == 0)
return null;
return selectedItems[0].Value;
}
/// <summary>
/// 根据指定的绑定项对象
/// 设置当前列表中选定的项
/// </summary>
/// <param name="obj"></param>
public void SetSelectedValue(object obj)
{
if (obj == null)
{
ClearSelect();
return;
}
var items = (from item in _items where item.Value == obj select item).ToList();
if (items.Count == 0)
{
Debug.Assert(false, "没有指定的项");
return;
}
var oldSelectedItems = GetSelectedItems();
//这里为什么用foreach
//考虑到多个项绑定到同一个对象的情况,不过理论上讲不应该出现这种情况
SuspendLayout();
ClearSelect();
foreach (var item in items)
{
item.Selected = true;
}
ResumeLayout();
if (items.SequenceEqual(oldSelectedItems) == false)
OnSelectedItemChanged();
}
/// <summary>
/// 获取当前选中的所有项的绑定对象集合
/// 如果当前没有选中任何项,返回空集合
/// </summary>
/// <returns></returns>
public List<object> GetSelectedValues()
{
List<object> selectedValues = new List<object>();
List<ShengListViewItem> selectedItems = GetSelectedItems();
foreach (var item in selectedItems)
{
selectedValues.Add(item.Value);
}
return selectedValues;
}
/// <summary>
/// 取消所有项的选择
/// </summary>
public void ClearSelect()
{
bool suspend = false;
if (this.Suspend == false)
{
this.SuspendLayout();
suspend = true;
}
foreach (var selectedItem in GetSelectedItems())
{
selectedItem.Selected = false;
}
if (suspend)
this.ResumeLayout();
}
/// <summary>
///
/// </summary>
/// <param name="list"></param>
public void DataBind(IList list)
{
if (list == null)
{
Debug.Assert(false, "list 为 null");
throw new ArgumentNullException();
}
SuspendLayout();
Items.Clear();
foreach (var item in list)
{
this.Items.Add(new ShengListViewItem(item));
}
ResumeLayout();
}
/// <summary>
///
/// </summary>
public void Clear()
{
SuspendLayout();
Items.Clear();
ResumeLayout();
}
#endregion
#region private
private void Hover(Point location)
{
ShengListViewHitInfo hitInfo = _layoutManager.HitTest(location);
if (hitInfo.ItemHit)
{
HoveredItem = Items[hitInfo.ItemIndex];
}
else
{
HoveredItem = null;
}
}
private void SetLayoutManager(ShengListViewLayoutManager layoutManager)
{
if (_layoutManager == layoutManager)
return;
if (_layoutManager != null)
_layoutManager.Dispose();
_layoutManager = layoutManager;
Refresh();
}
#endregion
#region protected
/// <summary>
/// 获取创建控件句柄时所需要的创建参数
/// </summary>
protected override CreateParams CreateParams
{
get
{
//设置控件的边框样式
CreateParams p = base.CreateParams;
p.Style &= ~WS_BORDER;
p.ExStyle &= ~WS_EX_CLIENTEDGE;
if (_borderStyle == BorderStyle.Fixed3D)
p.ExStyle |= WS_EX_CLIENTEDGE;
else if (_borderStyle == BorderStyle.FixedSingle)
p.Style |= WS_BORDER;
return p;
}
}
/// <summary>
///
/// </summary>
/// <param name="e"></param>
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
//_layoutManager.Update();
}
#region Mouse
/// <summary>
///
/// </summary>
/// <param name="e"></param>
protected override void OnMouseDown(MouseEventArgs e)
{
SuspendLayout();
if (Focused == false)
Focus();
LeftButton = (e.Button & MouseButtons.Left) == MouseButtons.Left;
RightButton = (e.Button & MouseButtons.Right) == MouseButtons.Right;
LastMouseDownLocation = e.Location;
_layoutManager.MouseDown(e);
ResumeLayout();
base.OnMouseDown(e);
}
/// <summary>
///
/// </summary>
/// <param name="e"></param>
protected override void OnMouseUp(MouseEventArgs e)
{
if ((e.Button & MouseButtons.Left) == MouseButtons.Left)
LeftButton = false;
if ((e.Button & MouseButtons.Right) == MouseButtons.Right)
RightButton = false;
SuspendLayout();
_layoutManager.MouseUp(e);
ResumeLayout();
//显示上下文菜单
bool rightButton = (e.Button & MouseButtons.Right) == MouseButtons.Right;
if (rightButton && this.ContextMenuStrip != null)
{
this.ContextMenuStrip.Show(this.PointToScreen(e.Location));
}
base.OnMouseUp(e);
}
/// <summary>
///
/// </summary>
/// <param name="e"></param>
protected override void OnMouseMove(MouseEventArgs e)
{
// if (_toolTip.Active)
// _toolTip.Hide(this);
SuspendLayout();
//如果处于框选状态不处理Hover
if (_layoutManager.MouseSelecting == false)
{
Hover(e.Location);
}
_layoutManager.MouseMove(e);
ResumeLayout();
base.OnMouseMove(e);
}
/// <summary>
///
/// </summary>
/// <param name="e"></param>
protected override void OnMouseWheel(MouseEventArgs e)
{
SuspendLayout();
_layoutManager.OnMouseWheel(e);
Hover(e.Location);
NeedPaint();
ResumeLayout();
base.OnMouseWheel(e);
}
/// <summary>
///
/// </summary>
/// <param name="e"></param>
protected override void OnMouseDoubleClick(MouseEventArgs e)
{
if (ItemDoubleClick != null)
{
ShengListViewHitInfo hitInfo = _layoutManager.HitTest(e.Location);
if (hitInfo.ItemHit)
{
ShengListViewItem item = Items[hitInfo.ItemIndex];
OnItemDoubleClick(item);
}
}
base.OnMouseDoubleClick(e);
}
/// <summary>
///
/// </summary>
/// <param name="e"></param>
protected override void OnMouseHover(EventArgs e)
{
//Point toolTipPoint = this.PointToClient(Cursor.Position);
//_toolTip.Show("ff", this, toolTipPoint);
base.OnMouseHover(e);
}
#endregion
#region Key
/// <summary>
///
/// </summary>
/// <param name="keyData"></param>
/// <returns></returns>
protected override bool IsInputKey(Keys keyData)
{
if ((keyData & Keys.Left) == Keys.Left ||
(keyData & Keys.Right) == Keys.Right ||
(keyData & Keys.Up) == Keys.Up ||
(keyData & Keys.Down) == Keys.Down)
return true;
else
return base.IsInputKey(keyData);
}
/// <summary>
///
/// </summary>
/// <param name="e"></param>
protected override void OnKeyDown(KeyEventArgs e)
{
ShiftKey = (e.Modifiers & Keys.Shift) == Keys.Shift;
ControlKey = (e.Modifiers & Keys.Control) == Keys.Control;
_layoutManager.OnKeyDown(e);
base.OnKeyDown(e);
}
/// <summary>
///
/// </summary>
/// <param name="e"></param>
protected override void OnKeyUp(KeyEventArgs e)
{
ShiftKey = (e.Modifiers & Keys.Shift) == Keys.Shift;
ControlKey = (e.Modifiers & Keys.Control) == Keys.Control;
_layoutManager.OnKeyUp(e);
base.OnKeyUp(e);
}
#endregion
#region Focus
/// <summary>
///
/// </summary>
/// <param name="e"></param>
protected override void OnGotFocus(EventArgs e)
{
base.OnGotFocus(e);
Refresh();
}
/// <summary>
///
/// </summary>
/// <param name="e"></param>
protected override void OnLostFocus(EventArgs e)
{
base.OnLostFocus(e);
Refresh();
}
#endregion
#region Paint
/// <summary>
///
/// </summary>
/// <param name="e"></param>
protected override void OnPaint(PaintEventArgs e)
{
if (_layoutManager != null)
{
_layoutManager.Render(e.Graphics);
}
//Size size1 = new Size(100, 100);
//Size size2 = new Size(50, 50);
//e.Graphics.DrawRectangle(Pens.Black, new Rectangle(new Point(10, 10), size1));
//size1 = Size.Add(size1, size2);
//e.Graphics.DrawRectangle(Pens.Red, new Rectangle(new Point(10, 10), size1));
}
#endregion
/// <summary>
///
/// </summary>
/// <param name="disposing"></param>
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
}
#endregion
#endregion
#region
/// <summary>
/// 更改了选择的项
/// </summary>
public event EventHandler SelectedItemChanaged;
/// <summary>
/// 双击项
/// </summary>
public event EventHandler<ShengListViewItemDoubleClickEventArgs> ItemDoubleClick;
/// <summary>
/// 项被删除
/// </summary>
public event EventHandler<ShengListViewItemsRemovedEventArgs> ItemsRemoved;
/// <summary>
/// 通过外能事件获取用于绘制项的文本
/// </summary>
public event EventHandler<ShengListViewGetItemTextEventArgs> ItemTextGetting;
#endregion
}
}