复制/粘贴数据库对象

介绍
本文将遵循一个简单的场景,一个Restaurant对象类,它有几个属性,包括a
List<比;HealthScore对象。
HealthScore对象将被复制和粘贴。就像示例中的类一样,它可以标记为Serializable,但这只是假设
在本文中,抽象概念对象将包含进一步的项,这些项排除了它是二进制可序列化的。因此,我们
还要实现一个姊妹对象ClipboardHealthScore。我们将来回转换这个姊妹对象,以便存储在剪贴板上。
我们还将看到如何劫持windows消息que来捕获剪贴板中的更改,从而允许我们动态地控制粘贴
按钮,基于剪贴板是否包含有效的可粘贴数据。
背景
为了将自定义对象存储在系统剪贴板中,它必须是二进制可序列化的。通常,在数据绑定对象中,可能会包含一些被排除的内容
它来自序列化资格,例如事件、专门的getter或属性setter以及其他此类性质的东西。因此,我们假设
我们要存储的对象不满足序列化要求。
使用的代码
首先,让我们花一点时间来讨论用于复制和粘贴函数的数据对象。我们感兴趣的产品是
HealthScore类型。
现在,就像我之前说的,在这种情况下,我们可以简单地使用我们的数据对象,因为它符合二进制序列化的条件,但我们假设它不符合,
作为现实生活中的对象,它很可能会更加复杂。出于这个原因,我们实现了一个姐妹类,以便于在剪贴板中进行存储。首先,我们的数据对象:
隐藏,复制Codepublic class HealthScore
{
private int _value;
public HealthScore() { _value = 0; }
public HealthScore(int value) { _value = value; }
public int Value { get { return _value; } set { _value = value; } }
}
我们的姐妹类,ClipboardHealthScore将几乎相同,除了我们会扩大
IComareable< HealthScore>并包含一个int属性
SourceIndex。
这将允许我们在将集合存储到剪贴板之前对其进行排序。这很重要,因为当您单步执行选中单元格时
DataGridView,
您将按照它们被选中的顺序获得它们,而不是按照它们在表中出现的顺序。按索引排序将允许我们的粘贴在相同的顺序
与源表中的一样。延长IComparable<比;需要实施
CompareTo(ClipboardHealthScore a, ClipboardHealthScore b)方法,需要
根据是否返回1、-1或0被认为大于, 1表示是,-1表示否,如果它们相等,则为零。
另外,我们需要将这个类标记为Serializable:
隐藏,复制Code[Serializable]
public class ClipboardHealthScore : IComparable;
{
private int _value;
private int _sourceindex;
public ClipboardHealthScore() { _value = _sourceindex= 0; }
public ClipboardHealthScore(int value, int sourceindex) { _value = value; _sourceindex = sourceindex; }
public int Value { get { return _value; } set { _value = value; } }
public int SourceIndex { get { return _sourceindex; } set { _sourceindex = value; } }
public int CompareTo(ClipboardHealthScore a, ClipboardHealthScore b)
{
if (a.SourceIndex > b.SourceIndex) return 1;
else if (a.SourceIndex < b.SourceIndex) return -1;
else return 0;
}
}
另外,一个正常的列表。集合是不可序列化的,这只是因为它的基类没有这样标记。因此,我们需要创建一个类
扩展List< T>要将我们的ClipboardHealthScore条目存储在其中,并将其标记为Serializable:
隐藏,复制Code[Serializable]
public class ClipboardHealthScoreCollection : List
{
public ClipboardHealthScoreCollection() { }
}
现在复制,我们将获取选定的健康分数,将它们转换为
并将它们存储在剪贴板上。要粘贴,我们将检索
clipboardhealthscore从剪贴板返回并将其转换为正常
并将其添加到我们的数据对象中。
首先,让我们复制我们选择的项目:
隐藏,复制Codeprivate void copybutton_Click(object sender, EventArgs e)
{
// First lets store each selected cell’s row index in a list
// making sure not to store duplicates
List selectedindexes = new List();
foreach (DataGridViewCell cell in this.dataGridView1.SelectedCells)
{
if (!selectedindexes.Contains(c.RowIndex)) selectedindexes.Add(cell.RowIndex);
}
// Now we step through these indices converting each item to the ClipboardHealthScore
// and putting it into a collection, then add the collection to the Clipboard
ClipboardHealthScoreCollection copyitems = new ClipboardHealthScoreCollection();
foreach(int i in selectedindexes)
{
copyitems.Add(new ClipboardHealthScore(this.healthScoreBindingSource[i].Value, i));
}
copyitems.Sort();
DataObject dobj = new DataObject();
dobj.SetData(typeof(ClipboardHealthScoreCollection), copyitems);
Clipboard.SetDataObject(dobj);
}
不是太难。现在让我们处理粘贴这些项目到我们的数据集:
隐藏,复制Codeprivate void pastebutton_Click(object sender, EventArgs e)
{
DataObject dobj = (DataObject)Clipboard.GetDataObject();

if (dobj.GetDataPresent(typeof(ClipboardHealthScoreCollection)))
{
    ClipboardHealthScoreCollection pastescores = 
      (dobj.GetData(typeof(ClipboardHealthScoreCollection))as ClipboardHealthscoreCollection);

    HealthScore newscore;
    foreach(ClipboardHealthScore hs in pastescores)
    {
        newscore = new HealthScore();
        newscore.Value = hs.Value;
        AddHealthScore(newscore);
    }
}

}
最后,让我们讨论一下如何设置您的表单来侦听剪贴板的变化,从而允许您相应地处理粘贴控件。如果您正在制作一个MDI应用程序,
我建议您将MDI父窗体设置为侦听器。
首先,我们需要定义两个常量int变量来定义我们想要监听的Windows消息。
隐藏,复制Codeprivate const int WM_DRAWCLIPBOARD = 0x0308;
privaet const int WM_CHANGECBCHAIN = 0x030D;
你还需要一个IntPtr变量来保存下一个监听器的句柄:
隐藏,复制Codeprivate IntPtr _NextClipboardViewer;
你需要为互操作服务添加一个using语句:
隐藏,复制Codeusing System.Runtime.InteropServices;
接下来你需要设置PInvoke方法,你需要设置剪贴板监听器:
隐藏,复制Code[DllImport(“User32.dll”), CharSet = CharSet.Auto)]]
private static extern IntPtr SetClipboardViewer(IntPtr newviewer);

[DllImport(“User32.dll”), CharSet = CharSet.Auto)]
private static extern IntPtr ChangeClipboardChain(IntPtr hwnd, IntPtr newviewer);

[DllImport(“User32.dll”), CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hwnd, int m, IntPtr wParam, IntPtr lParam);
SetClipboardViewer将把给定的句柄插入到剪贴板警告链中,并在一行中返回下一个查看器的句柄。我们将使用这个方法来设置
您的表单作为侦听器,我建议在Form_Load 事件中调用它。
隐藏,复制Codeprivate void Form_Load(object sender, EventArgs e)
{
_NextClipboardViewer = SetClipboardViewer(this.Handle);
}
ChangeClipboardChain将从链中删除给定的句柄,并将最后一个查看器连接到下一个指定的查看器。
当侦听器窗体关闭时,我们将使用它。如果您不处理Form_Closing事件,您可以在这里这样做。如果你是,你有一些条件可以消去
表单关闭,我建议使用Form_Closed中的这个方法。这样,我们只有在关闭表单时才会分离。
隐藏,复制Codeprivate void Form_Closed(object sender, FormClosedEventArgs e)
{
ChangeClipboardChain(this.Handle, _NextClipboardViewer);
}
SendMessage将发送一条windows消息。我们将在拦截消息时使用它。一旦我们采取行动,我们就会会把消息传下去。
所以现在我们需要覆盖WndProc(ref m);方法。如果传入的消息与我们定义的两种类型中的一种匹配,我们希望处理它们,并将它们传递下去:
隐藏,复制Codeprotected override void WndProc(ref m)
{
switch(m.Msg)
{
case WM_DRAWCLIPBOARD:
// here a change has been made in the contents of clipboard, lets evaluate
pastebutton.Enable = Clipboard.ContainData(typeof(ClipboardHealthScoreCollection).FullName));
SendMessage(_NextClipboardViewer, m.Msg, m.WParam, m.LParam);
break;
case WM_CHANGECBCHAIN:
// here a change has been made in the viewer chain
if (m.WParam == _NextClipboardViewer) _NextClipboardViewer = m.LParam;
else SendMessage(_NextClipboardViewer, m.Msg, m.WParam, m.LParam);
break;
default:
base.WndProc(m);
break;
}
}

本文转载于:http://www.diyabc.com/frontweb/news266.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值