1

我不知道为什么 GetData() 方法需要 Type 的参数,我认为 Type 是指定对象应该是哪个类/类型。我有一个名为 GraphicsPathWrap 的结构,它通过实现 ISerializable 使其可序列化。我尝试了以下复制功能:

private void Copy(GraphicsPathWrap gpw){
  DataObject obj = new DataObject();
  obj.SetData(typeof(GraphicsPathWrap), gpw);
  Clipboard.SetDataObject(obj);
}

然后尝试了以下粘贴功能:

private GraphicsPathWrap Paste()
{
  return (GraphicsPathWrap)Clipboard.GetDataObject().GetData(typeof   (GraphicsPathWrap));
}

它应该可以工作,但是 GetData(...) 返回一个 MemoryStream 类型的对象,并且引发了 InvalidCastException。我不明白为什么它是 MemoryStream 的类型。我认为它应该可以转换为 GraphicsPathWrap?我可以通过使用 BinaryFormatter 反序列化 MemoryStream 来解决这个问题,但是当剪贴板不能为我做所有事情时,这太荒谬了?

谢谢!

4

4 回答 4

2

EDIT : I've exactly simulated your situation, the thing is which was saying MemoryStream when you have implemented the ISerializable Interface and hadn't deserialized it properly.

The GetData() Returns Memory Stream in this below scenario :

      [Serializable]
        public struct GraphicsPathWrap : ISerializable
        {
            private static string myValue = "This is the value of the class";             

            // Creates a property to retrieve or set the value. 
            public string MyObjectValue
            {
                get
                {
                    return myValue;
                }
                set
                {
                    myValue = value;
                }
            }

            #region ISerializable Members

            public void GetObjectData(SerializationInfo info, StreamingContext context)
            {

            }

            #endregion
        } 

Then, I implemented serialization\deserialization properly when GetData() gives the correct type object

[Serializable]
        public struct GraphicsPathWrap : ISerializable
        {
            private static string myValue = "This is the value of the class";

            public GraphicsPathWrap(SerializationInfo info, StreamingContext ctxt)  // Deserialization Constructor
            {
                myValue = (string)info.GetValue("MyValue", typeof(string));
            }

            // Creates a property to retrieve or set the value. 
            public string MyObjectValue
            {
                get
                {
                    return myValue;
                }
                set
                {
                    myValue = value;
                }
            }

            #region ISerializable Members

            public void GetObjectData(SerializationInfo info, StreamingContext context)
            {
                info.AddValue("MyValue", myValue); // Serialize the value
            }

            #endregion
        }

I hope the above answer will help you

于 2013-03-09T08:55:36.413 回答
1

Clipboard.SetDataObject(object data) 方法名称有点误导,因为它没有专门要求 DataObject 作为参数,而只是一个必须可序列化的 Object。

您可以尝试像这样直接传递 gpw:

private void Copy(GraphicsPathWrap gpw){
  Clipboard.SetDataObject(gpw);
}

如果 GraphicsPathWrap 是可序列化的,它应该可以工作。

编辑:在测试我自己之后,事实证明该方法可以双向工作,要么直接传递 Serializable 对象,要么将其封装在 DataObject 中。我通过检查特定剪贴板方法的 .Net 源代码确认了这一点,我在其中发现了这一点:

if (data is DataObject) 
{
      dataObject = (DataObject)data; 
}

因此,正如 Ramesh 在另一个答案中所说,您可能需要检查您的对象是否正确设置为 Seriaizable。

于 2013-03-09T08:44:17.363 回答
1

我正在使用Clipboard.GetData一个类型的对象SerializedClipboardFragment——这是我自己的一个类型,一个类,我用[Serializable()]属性标记了它:

[Serializable()]
public class SerializedClipboardFragment
{
    readonly string[] m_ancestors;
    readonly string m_fragment;
    readonly int m_numberOfNodes;
    readonly bool m_isInsertingBlock;
    readonly bool m_isInsertingTable;

    public SerializedClipboardFragment(
        string[] ancestors,
        string fragment,
        int numberOfNodes,
        bool isInsertingBlock,
        bool isInsertingTable
        )
    {
        m_ancestors = ancestors;
        m_fragment = fragment;
        m_numberOfNodes = numberOfNodes;
        m_isInsertingBlock = isInsertingBlock;
        m_isInsertingTable = isInsertingTable;
    }

    internal static DataFormats.Format s_format;
    static SerializedClipboardFragment()
    {
        s_format = DataFormats.GetFormat(typeof(SerializedClipboardFragment).FullName);
    }

    ... etc -- various get-only properties ...
}

我从剪贴板获取此数据的代码如下所示:

    public static SerializedClipboardFragment getSerializedFragment()
    {
        if (!Clipboard.ContainsData(SerializedClipboardFragment.s_format.Name))
        {
            return null;
        }

        object o = Clipboard.GetData(SerializedClipboardFragment.s_format.Name);
        return (SerializedClipboardFragment)o;
    }

当我测试这个时,我发现它通常有效。

但它有时会在我的自动回归测试中失败,我尝试在设置后立即从剪贴板获取数据......例如,它可能会在 30 次连续成功的 set-then-get 尝试后失败。

如果它失败了,就像你描述的那样,即对象是MemoryStream.

请注意,它不应该因为Clipboard.ContainsData最近返回而失败true

我意识到只有一个系统剪贴板;运行此测试时,我的手不在键盘上,发生这种情况时我并不想自己干扰剪贴板。

无论如何,如果我编写如下代码,问题似乎就消失了:

    public static SerializedClipboardFragment getSerializedFragment()
    {
        if (!Clipboard.ContainsData(SerializedClipboardFragment.s_format.Name))
        {
            return null;
        }
        // sometimes return MemoryStream object instead under automated-testing
        // possibly a timing problem
        object o = null;
        for (int i = 0; i < 10; ++i)
        {
            o = Clipboard.GetData(SerializedClipboardFragment.s_format.Name);
            if (o is SerializedClipboardFragment)
                return (SerializedClipboardFragment)o;
            System.Threading.Thread.Sleep(100);
        }
        return (SerializedClipboardFragment)o;
    }

因此,除非我弄错了,否则这可能是一些令人反感的计时错误,与在剪贴板中存储自定义数据类型相关。

于 2017-12-17T22:07:57.407 回答
0
[DataObject(true)]
    public class EmployeeDAL
    {
        [DataObjectMethod(DataObjectMethodType.Update, true)]
        public int UpdateEmployeeSalary(int percentage, int deptid, int posid)
        {
            OracleConnection con = new OracleConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);
            OracleCommand cmd = new OracleCommand("GIVE_RAISE_SP", con);
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Parameters.AddWithValue("PV_PERCENTAGE_RAISE_I", OracleType.Int32).Value = percentage;
            cmd.Parameters.AddWithValue("PV_POSITIONID_I", OracleType.Int32).Value = posid;
stac            cmd.Parameters.AddWithValue("PV_DEPTID_I", OracleType.Int32).Value = deptid;
            cmd.Parameters.AddWithValue("PV_NUM_EMPLOYEES_O", OracleType.Int32).Direction = ParameterDirection.Output;

            OracleDataAdapter da = new OracleDataAdapter(cmd);

            try
            {
                con.Open();
                da.UpdateCommand = cmd;
                cmd.ExecuteNonQuery();
            }
            catch (Exception)
            {

            }
            finally
            {
                con.Close();
            }

            return Convert.ToInt32(cmd.Parameters["PV_NUM_EMPLOYEES_O"].Value);
        }
于 2016-04-21T00:50:59.607 回答