zoukankan      html  css  js  c++  java
  • 复制/粘贴数据库对象

    介绍 本文将遵循一个简单的场景,一个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

  • 相关阅读:
    Linux下通过.desktop 文件创建桌面程序图标及文件编写方式(Desktop Entry文件概述)
    Ubuntu16.04进入挂起或休眠状态时按任何键都无法唤醒问题解决办法
    Ubuntu16.04+Gnome3 锁定屏幕快捷键无效解决办法
    A start job is running for Raise network interface(5min 13s )问题解决方法
    Ubuntu16.04 “有线未托管”有线网络不可用问题解决
    A start job is running for Network Manager wait online (29s / no limit) 等待30s解决办法
    Linux 串口终端调试工具minicom
    Linux 终端仿真程序Putty
    Oracle:在 debian9 上完美安装 oracle 10.2.0.5 x64
    从debian9、ubuntu18.04的deb包依赖来看,似乎不是那么好!!
  • 原文地址:https://www.cnblogs.com/Dincat/p/13437317.html
Copyright © 2011-2022 走看看