using CommonFroms.Properties;
using CommonLang;
using CommonLang.Xml;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
namespace CommonFroms.G2D.DataGrid
{
public class G2DPropertyGrid : System.Windows.Forms.PropertyGrid
{
private int descriptionAreaLineCount = 2;
private int descriptionAreaLineCountMin = 2;
private Control docComment = null;
private Control propertyGridView = null;
private ToolStrip tools;
private Type docCommentType = null;
private PropertyInfo linesProperty;
private bool sizeChangeIsFromUser = true;
private bool inited = false;
private Type last_field_decleard_type = null;
private ToolStripButton btn_copy;
private ToolStripButton btn_paste;
private ToolStripDropDownButton btn_paste_plus;
private ToolStripButton btn_cut;
private ToolStripButton btn_delete;
private ToolStripLabel lbl_copying;
///
/// Initializes a new instance of the CustomPropertyGrid class.
///
public G2DPropertyGrid()
{
this.ImeMode = ImeMode.On;
this.MinDescriptionAreaLineCount = 5;
foreach (Control control in this.Controls)
{
Type controlType = control.GetType();
if (controlType.Name == "DocComment")
{
this.docCommentType = controlType;
this.docComment = control;
this.linesProperty = this.docCommentType.GetProperty("Lines");
FieldInfo userSizedField = this.docCommentType.BaseType.GetField(
"userSized",
BindingFlags.Instance | BindingFlags.NonPublic);
userSizedField.SetValue(this.docComment, true);
this.docComment.SizeChanged += this.HandleDocCommentSizeChanged;
}
else if (controlType.Name == "PropertyGridView")
{
this.propertyGridView = control;
}
else if (controlType.Name == "ToolStrip")
{
this.tools = control as ToolStrip;
}
}
this.SelectedGridItemChanged += G2DPropertyGrid_SelectedGridItemChanged;
if (tools != null)
{
InitTools();
}
}
public void SetSelectedObject(object value, params IG2DPropertyAdapter[] adds)
{
base.SelectedObject = new G2DPropertyDescriptor(value, adds);
}
public object GetSelectedValue()
{
if (base.SelectedObject is G2DPropertyDescriptor)
{
return (base.SelectedObject as G2DPropertyDescriptor).EditData;
}
return base.SelectedObject;
}
private void G2DPropertyGrid_SelectedGridItemChanged(object sender, SelectedGridItemChangedEventArgs e)
{
this.OnRefreshHistoryValiable(SelectedGridItem);
}
protected override void OnPropertyValueChanged(PropertyValueChangedEventArgs e)
{
base.OnPropertyValueChanged(e);
this.Refresh();
}
protected override void OnInvalidated(InvalidateEventArgs e)
{
base.OnInvalidated(e);
if (!inited)
{
inited = true;
this.DescriptionAreaLineCount = this.MinDescriptionAreaLineCount;
}
}
//------------------------------------------------------------------------------------------------------
#region _key_events_
protected override bool ProcessCmdKey(ref Message msg, Keys kd)
{
if (Keyboard.IsCtrlDown)
{
Keys keyData = kd ^ Keys.Control;
switch (keyData)
{
case Keys.C:
if (ProcessKeyDown_CtrlC != null)
{
ProcessKeyDown_CtrlC.Invoke(this, new KeyEventArgs(keyData));
}
DoCopy();
return true;
case Keys.V:
if (ProcessKeyDown_CtrlV != null)
{
ProcessKeyDown_CtrlV.Invoke(this, new KeyEventArgs(keyData));
}
DoPaste();
return true;
case Keys.X:
if (ProcessKeyDown_CtrlX != null)
{
ProcessKeyDown_CtrlX.Invoke(this, new KeyEventArgs(keyData));
}
DoCut();
return true;
}
}
switch (kd)
{
case Keys.Delete:
if (ProcessKeyDown_Delete != null)
{
ProcessKeyDown_Delete.Invoke(this, new KeyEventArgs(kd));
}
DoDelete();
return true;
}
return base.ProcessCmdKey(ref msg, kd);
}
public delegate void KeyDownProcessHandler(object sender, KeyEventArgs e);
///
/// 键盘Ctrl+C触发
///
public event KeyDownProcessHandler ProcessKeyDown_CtrlC;
///
/// 键盘Ctrl+V触发
///
public event KeyDownProcessHandler ProcessKeyDown_CtrlV;
///
/// 键盘Ctrl+X触发
///
public event KeyDownProcessHandler ProcessKeyDown_CtrlX;
///
/// 键盘Del触发
///
public event KeyDownProcessHandler ProcessKeyDown_Delete;
#endregion
//------------------------------------------------------------------------------------------------------
#region _tools_
private void InitTools()
{
tools.CanOverflow = false;
tools.LayoutStyle = ToolStripLayoutStyle.Flow;
// try
// {
// FieldInfo btnViewPropertyPagesField = base.GetType().GetField("btnViewPropertyPages", BindingFlags.Instance);
// ToolStripButton btnViewPropertyPages = btnViewPropertyPagesField.GetValue(this) as ToolStripButton;
// btnViewPropertyPages.Visible = false;
// }
// catch (Exception err) { }
tools.Items.Add(new ToolStripSeparator());
tools.Items.Add(btn_copy = new ToolStripButton("复制", Resources.icons_copy));
tools.Items.Add(btn_paste = new ToolStripButton("粘贴", Resources.icons_paste));
tools.Items.Add(btn_cut = new ToolStripButton("剪切", Resources.icons_cut));
tools.Items.Add(btn_delete = new ToolStripButton("删除", Resources.icons_delete));
tools.Items.Add(new ToolStripSeparator());
tools.Items.Add(btn_paste_plus = new ToolStripDropDownButton("", Resources.icons_paste_plus));
tools.Items.Add(lbl_copying = new ToolStripLabel(""));
btn_paste_plus.ToolTipText = "粘贴自";
btn_paste_plus.ForeColor = System.Drawing.Color.Blue;
btn_paste_plus.DisplayStyle = ToolStripItemDisplayStyle.ImageAndText;
btn_paste_plus.DropDownItemClicked += Btn_paste_plus_DropDownItemClicked;
btn_paste_plus.DropDownOpening += Btn_paste_plus_DropDownOpening;
btn_paste_plus.AutoToolTip = true;
lbl_copying.ForeColor = System.Drawing.Color.Blue;
lbl_copying.Overflow = ToolStripItemOverflow.Never;
lbl_copying.AutoToolTip = true;
btn_delete.Visible = false;
btn_cut.DisplayStyle = ToolStripItemDisplayStyle.Image;
btn_copy.DisplayStyle = ToolStripItemDisplayStyle.Image;
btn_paste.DisplayStyle = ToolStripItemDisplayStyle.Image;
btn_delete.DisplayStyle = ToolStripItemDisplayStyle.Image;
btn_cut.Click += Btn_cut_Click; ;
btn_copy.Click += Btn_copy_Click;
btn_paste.Click += Btn_paste_Click;
btn_delete.Click += Btn_delete_Click;
}
private void RefreshToolTips(List list)
{
if (list != null && list.Count > 0)
{
CopyHistory.Entry current = list[0];
this.btn_paste_plus.Text = list.Count.ToString();
this.btn_paste_plus.ToolTipText = "粘贴自: " + current.lbl_text;
this.lbl_copying.Text = current.lst_text ;
this.lbl_copying.ToolTipText = current.lbl_text ;
this.btn_paste_plus.Visible = true;
this.lbl_copying.Visible = true;
}
else
{
this.btn_paste_plus.Visible = false;
this.lbl_copying.Visible = false;
}
}
///
/// 刷新粘贴可用项目
///
///
private void OnRefreshHistoryValiable(GridItem item)
{
if (item != null && item.PropertyDescriptor is IG2DPropertyDescriptor)
{
Type decleard_type = (item.PropertyDescriptor as IG2DPropertyDescriptor).DecleardFieldType;
if (!decleard_type.Equals(this.last_field_decleard_type))
{
this.last_field_decleard_type = decleard_type;
this.btn_paste_plus.DropDownItems.Clear();
List list = CopyHistory.GetHistoryList(decleard_type);
if (list != null && list.Count > 0)
{
foreach (var h in list)
{
var add = new ToolStripButton(h.lst_text);
add.AutoToolTip = true;
add.ToolTipText = h.lbl_text;
add.DisplayStyle = ToolStripItemDisplayStyle.Text;
add.ForeColor = (add.Enabled) ? System.Drawing.Color.Blue : System.Drawing.Color.Gray;
add.Tag = h;
btn_paste_plus.DropDownItems.Add(add);
}
RefreshToolTips(list);
return;
}
else
{
RefreshToolTips(null);
}
}
}
else
{
this.last_field_decleard_type = null;
RefreshToolTips(null);
}
}
private void OnRefreshHistoryAdded(GridItem item, bool new_item, List list)
{
if (list != null && list.Count > 0)
{
if (new_item)
{
CopyHistory.Entry current = list[0];
var add = new ToolStripButton(current.lst_text);
add.AutoToolTip = true;
add.ToolTipText = current.lbl_text;
add.DisplayStyle = ToolStripItemDisplayStyle.Text;
add.ForeColor = (add.Enabled) ? System.Drawing.Color.Blue : System.Drawing.Color.Gray;
add.Tag = current;
btn_paste_plus.DropDownItems.Insert(0, add);
}
RefreshToolTips(list);
}
else
{
RefreshToolTips(null);
}
}
private void Btn_delete_Click(object sender, EventArgs e)
{
DoDelete();
}
private void Btn_paste_Click(object sender, EventArgs e)
{
DoPaste();
}
private void Btn_copy_Click(object sender, EventArgs e)
{
DoCopy();
}
private void Btn_cut_Click(object sender, EventArgs e)
{
DoCut();
}
private void Btn_paste_plus_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
var history = e.ClickedItem.Tag as CopyHistory.Entry;
if (history != null)
{
DoPastePlus(history);
}
}
private void Btn_paste_plus_DropDownOpening(object sender, EventArgs e)
{
}
#endregion
//------------------------------------------------------------------------------------------------------
#region _copying_and_pasting_
public static int CopyHistoryLimit
{
get { return CopyHistory.CopyHistoryLimit; }
set { CopyHistory.CopyHistoryLimit = value; }
}
public static bool TryConvertTo(object src, Type targetType)
{
object target;
return TryConvertTo(src, targetType, out target);
}
public static bool TryConvertTo(object src, Type targetType, out object target)
{
if (targetType.IsInstanceOfType(src))
{
target = src;
return true;
}
if (targetType.IsPrimitive && src.GetType().IsPrimitive)
{
try
{
target = Convert.ChangeType(src, targetType);
if (targetType.IsInstanceOfType(target))
{
return true;
}
}
catch (Exception ) { }
}
target = null;
return false;
}
private static class CopyHistory
{
private static HashMap> copying_history = new HashMap>();
private static List copying_history_primitive = new List();
private static int max_history_count = 22;
public static int CopyHistoryLimit
{
get { return max_history_count; }
set { if (value >= 20) { max_history_count = value; } }
}
public static List GetHistoryList(Type decleard_type)
{
if (decleard_type.IsPrimitive && decleard_type.IsValueType && (!decleard_type.Equals(typeof(bool))))
{
return copying_history_primitive;
}
List ret = copying_history.Get(decleard_type);
return ret;
}
public static bool Add(object owner, GridItem item, out List out_list)
{
if (item != null && item.PropertyDescriptor is IG2DPropertyDescriptor)
{
IG2DPropertyDescriptor g2dpp = item.PropertyDescriptor as IG2DPropertyDescriptor;
if (item.Value != null)
{
var x = XmlUtil.ToString(XmlUtil.ObjectToXml(item.Value, "data", true));
List list = GetHistoryList(g2dpp.DecleardFieldType);
if (list != null)
{
foreach (var old in list)
{
if (old.data.Equals(item.Value) || old.EqualsXmlText(x))
{
old.Renew(owner);
list.Sort();
out_list = list;
return false;
}
}
}
else
{
list = new List();
copying_history.Put(g2dpp.DecleardFieldType, list);
}
var copying_value = new Entry(owner, x, item);
list.Add(copying_value);
list.Sort();
if (list.Count > max_history_count)
{
list.RemoveRange(max_history_count, list.Count - max_history_count);
}
out_list = list;
return true;
}
}
out_list = null;
return false;
}
public static Entry CurrentAvaliable(Type decleard_type)
{
List list = GetHistoryList(decleard_type);
if (list != null && list.Count > 0)
{
return list[0];
}
return null;
}
public static int GetHistoryListCount(Type decleard_type)
{
List ret = GetHistoryList(decleard_type);
if (ret != null)
{
return ret.Count;
}
return 0;
}
//----------------------------------------------------------------------------------
public class Entry : IComparable
{
public readonly object data;
private readonly string cvt_text;
private readonly string xml_text;
private readonly string lbl_suffix;
public DateTime time { get; private set; }
public string lbl_text { get; private set; }
public string lst_text { get; private set; }
internal Entry(object owner, string x, GridItem item)
{
this.time = DateTime.Now;
this.data = item.Value;
this.xml_text = x;
this.cvt_text = item.Value.ToString();
Type expect_type = item.Value.GetType();
try
{
if (item.PropertyDescriptor.Converter != null)
{
cvt_text = item.PropertyDescriptor.Converter.ConvertToString(item.Value);
}
if (item.PropertyDescriptor is IG2DPropertyDescriptor)
{
IG2DPropertyDescriptor g2dpp = item.PropertyDescriptor as IG2DPropertyDescriptor;
expect_type = g2dpp.DecleardFieldType;
}
}
catch (Exception )
{
this.lst_text = item.Value.ToString();
}
this.lst_text = string.Format("[{0}] {1}", expect_type.Name, cvt_text);
this.lbl_suffix = string.Format("{0} = {1}", item.Label, lst_text);
this.lbl_text = string.Format("{0}:{1}", owner, lbl_suffix);
Clipboard.SetText(cvt_text);
}
public void Renew(object owner)
{
this.time = DateTime.Now;
this.lbl_text = string.Format("{0}:{1}", owner, lbl_suffix);
Clipboard.SetText(cvt_text);
}
public bool CanConvertTo(Type decleard_type)
{
if (TryConvertTo(data, decleard_type))
{
return true;
}
return false;
}
public int CompareTo(Entry other)
{
return -this.time.CompareTo(other.time);
}
public object CloneData(Type decleard_type)
{
object value = XmlUtil.XmlToObject(data.GetType(), XmlUtil.FromString(xml_text), true);
object target;
if (TryConvertTo(value, decleard_type, out target))
{
return target;
}
return value;
}
public bool EqualsXmlText(string x)
{
return this.xml_text.Equals(x);
}
}
}
//----------------------------------------------------------------------------------
private void DoCopy()
{
GridItem item = SelectedGridItem;
if (item != null && item.PropertyDescriptor != null && item.Value != null)
{
List list;
bool new_item = CopyHistory.Add(SelectedObject, item, out list);
this.OnRefreshHistoryAdded(item, new_item, list);
}
}
private void DoPaste()
{
GridItem item = SelectedGridItem;
if (item != null && item.PropertyDescriptor is IG2DPropertyDescriptor)
{
IG2DPropertyDescriptor g2dpp = item.PropertyDescriptor as IG2DPropertyDescriptor;
var current = CopyHistory.CurrentAvaliable(g2dpp.DecleardFieldType);
if (current != null)
{
DoPastePlus(current);
}
}
}
private void DoPastePlus(CopyHistory.Entry copying)
{
GridItem item = SelectedGridItem;
if (item != null && (copying != null) && (item.PropertyDescriptor != null) && (!item.PropertyDescriptor.IsReadOnly))
{
if (item.PropertyDescriptor is IG2DPropertyDescriptor)
{
IG2DPropertyDescriptor g2dpp = item.PropertyDescriptor as IG2DPropertyDescriptor;
try
{
var target = copying.CloneData(g2dpp.DecleardFieldType);
if (target != null)
{
item.PropertyDescriptor.SetValue(g2dpp.ComponentData, target);
this.Refresh();
}
}
catch (Exception err)
{
MessageBox.Show(err.Message);
}
}
}
}
private void DoDelete()
{
GridItem item = SelectedGridItem;
if (item != null && (item.PropertyDescriptor != null) && (!item.PropertyDescriptor.IsReadOnly))
{
if (item.PropertyDescriptor is IG2DPropertyDescriptor)
{
IG2DPropertyDescriptor g2dpp = item.PropertyDescriptor as IG2DPropertyDescriptor;
if (!g2dpp.NotNull)
{
try
{
item.PropertyDescriptor.SetValue(g2dpp.ComponentData, null);
this.Refresh();
}
catch (Exception err)
{
MessageBox.Show(err.Message);
}
}
else if (g2dpp.FieldValue != null)
{
if (g2dpp.DecleardFieldType.IsArray)
{
var array = (Array)g2dpp.FieldValue;
Array.Clear(array, 0, array.Length);
}
else if (g2dpp.DecleardFieldType.GetInterface(typeof(IDictionary).Name) != null)
{
var map = (IDictionary)g2dpp.FieldValue;
map.Clear();
}
else if (g2dpp.DecleardFieldType.GetInterface(typeof(IList).Name) != null)
{
var list = (IList)g2dpp.FieldValue;
list.Clear();
}
try
{
item.PropertyDescriptor.SetValue(g2dpp.ComponentData, g2dpp.FieldValue);
this.Refresh();
}
catch (Exception err)
{
MessageBox.Show(err.Message);
}
}
else
{
MessageBox.Show("字段不可删除!");
}
}
}
}
private void DoCut()
{
DoCopy();
DoDelete();
}
#endregion
//------------------------------------------------------------------------------------------------------
#region _description_
///
/// Occurs when the description area size is changed by the user.
///
public event EventHandler UserChangedDescriptionAreaSize;
///
/// 设置最小默认注释行数量
///
public int MinDescriptionAreaLineCount
{
get
{
return this.descriptionAreaLineCountMin;
}
set
{
if (value <= 0)
{
throw new ArgumentException("The value cannot be less than zero.");
}
this.descriptionAreaLineCountMin = value;
}
}
///
/// Gets or sets the description area line count.
///
/// The description area line count.
/// If value is less than zero.
/// If not of the all objects required to set the field were found.
public int DescriptionAreaLineCount
{
get
{
return this.descriptionAreaLineCount;
}
set
{
if (!inited)
{
return;
}
if (value < MinDescriptionAreaLineCount)
{
throw new ArgumentException("The value cannot be less than " + MinDescriptionAreaLineCount + ".");
}
if (this.docCommentType == null ||
this.docComment == null ||
this.propertyGridView == null ||
this.linesProperty == null)
{
throw new TypeLoadException("Not all of the objects required to set the field were found.");
}
try
{
int oldDocCommentHeight = this.docComment.Height;
int oldValue = this.DescriptionAreaLineCount;
this.linesProperty.SetValue(this.docComment, value, null);
int difference = this.docComment.Height - oldDocCommentHeight;
if (this.docComment.Top - difference > this.propertyGridView.Top)
{
this.sizeChangeIsFromUser = false;
this.propertyGridView.Height -= difference;
this.docComment.Top -= difference;
this.descriptionAreaLineCount = value;
this.sizeChangeIsFromUser = true;
}
else
{
this.linesProperty.SetValue(this.docComment, oldValue, null);
}
}
catch (TargetInvocationException)
{
}
this.Refresh();
}
}
///
/// Gets or sets the height of the description area.
///
/// The height of the description area.
public int DescriptionAreaHeight
{
get
{
return this.docComment.Height;
}
set
{
if (!inited)
{
return;
}
int difference = value - this.docComment.Height;
if (this.docComment.Top - difference > this.propertyGridView.Top)
{
this.docComment.Height = value;
this.docComment.Top -= difference;
this.propertyGridView.Height -= difference;
this.Refresh();
}
}
}
///
/// Raises the UserChangedDescriptionAreaSize event.
///
/// The System.EventArgs instance containing the event data.
protected void OnUserChangedDescriptionAreaSize(EventArgs e)
{
EventHandler handler = this.UserChangedDescriptionAreaSize;
if (handler != null)
{
handler(this, e);
}
}
///
/// Handles this.docComment.SizeChanged.
///
/// The sender.
/// The System.EventArgs instance containing the event data.
private void HandleDocCommentSizeChanged(object sender, EventArgs e)
{
if (this.sizeChangeIsFromUser)
{
try
{
this.descriptionAreaLineCount = (int)this.linesProperty.GetValue(this.docComment, null);
this.OnUserChangedDescriptionAreaSize(EventArgs.Empty);
}
catch (TargetInvocationException)
{
}
}
}
#endregion
//------------------------------------------------------------------------------------------------------
}
}