复制/粘贴数据库对象

介绍 本文将遵循一个简单的场景,一个Restaurant对象类,它有几个属性,包括a List<比;HealthScore对象。 HealthScore对象将被复制和粘贴。就像示例中的类一样,它可以标记为Serializable,但这只是假设 在本文中,抽象概念对象将包含进一步的项,这些项排除了它是二进制可序列化的。因此,我们 还要实现一个姊妹对象ClipboardHealthScore。我们将来回转换这个姊妹对象,以便存储在剪贴板上。 我们还将看到如何劫持windows消息que来捕获剪贴板中的更改,从而允许我们动态地控制粘贴 按钮,基于剪贴板是否包含有效的可粘贴数据。 背景 为了将

  

 

自定义对象存储在系统剪贴板中,它必须是二进制可序列化的。通常,在数据绑定对象中,可能会包含一些被排除的内容 它来自序列化资格,例如事件、专门的getter或属性setter以及其他此类性质的东西。因此,我们假设 我们要存储的对象不满足序列化要求。 使用的代码 首先,让我们花一点时间来讨论用于复制和粘贴函数的数据对象。我们感兴趣的产品是 HealthScore类型。 现在,就像我之前说的,在这种情况下,我们可以简单地使用我们的数据对象,因为它符合二进制序列化的条件,但我们假设它不符合, 作为现实生活中的对象,它很可能会更加复杂。出于这个原因,我们实现了一个姐妹类,以便于在剪贴板中进行存储。首先,我们的数据对象: 隐藏,复制Code

public 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)方法,需要 根据是否<a>返回1、-1或0被认为大于<b>, 1表示是,-1表示否,如果它们相等,则为零。 另外,我们需要将这个类标记为Serializable: 隐藏,复制Code

[Serializable]
public class ClipboardHealthScore : IComparable<ClipboardHealthScore>;
{
    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<ClipboardHealthScore>
{
    public ClipboardHealthScoreCollection() { }
}

现在复制,我们将获取选定的健康分数,将它们转换为 并将它们存储在剪贴板上。要粘贴,我们将检索 clipboardhealthscore从剪贴板返回并将其转换为正常 并将其添加到我们的数据对象中。 首先,让我们复制我们选择的项目: 隐藏,复制Code

private 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<Int32> selectedindexes = new List<Int32>();
    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);
}

不是太难。现在让我们处理粘贴这些项目到我们的数据集: 隐藏,复制Code

private 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消息。 隐藏,复制Code

private const int WM_DRAWCLIPBOARD = 0x0308;
privaet const int WM_CHANGECBCHAIN = 0x030D;

你还需要一个IntPtr变量来保存下一个监听器的句柄: 隐藏,复制Code

private IntPtr _NextClipboardViewer; 

你需要为互操作服务添加一个using语句: 隐藏,复制Code

using 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 事件中调用它。 隐藏,复制Code

private void Form_Load(object sender, EventArgs e)
{
    _NextClipboardViewer = SetClipboardViewer(this.Handle);
}

ChangeClipboardChain将从链中删除给定的句柄,并将最后一个查看器连接到下一个指定的查看器。 当侦听器窗体关闭时,我们将使用它。如果您不处理Form_Closing事件,您可以在这里这样做。如果你是,你有一些条件可以消去 表单关闭,我建议使用Form_Closed中的这个方法。这样,我们只有在关闭表单时才会分离。 隐藏,复制Code

private void Form_Closed(object sender, FormClosedEventArgs e)
{
    ChangeClipboardChain(this.Handle, _NextClipboardViewer);
}

SendMessage将发送一条windows消息。我们将在拦截消息时使用它。一旦我们采取行动,我们就会会把消息传下去。 所以现在我们需要覆盖WndProc(ref m);方法。如果传入的消息与我们定义的两种类型中的一种匹配,我们希望处理它们,并将它们传递下去: 隐藏,复制Code

protected 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

posted @ 2020-08-05 01:29  Dincat  阅读(266)  评论(0编辑  收藏  举报