【问题标题】:C# Backing Up And Restoring ClipboardC# 备份和恢复剪贴板
【发布时间】:2011-06-07 08:21:55
【问题描述】:

我有一个使用剪贴板的程序,但我想在完成后将剪贴板恢复到以前的状态。

这是我的代码:

IDataObject temp = Clipboard.GetDataObject();

//Some stuff that change Cliboard here
Clipboard.SetText("Hello");
//Some stuff that change Cliboard here

Clipboard.SetDataObject(temp);

但是如果我复制文本并运行这段代码,我在记事本上什么也得不到。

注意:我不能使用 Clipboard.Contains,因为我想完全保留剪贴板以前的样子,即使用户复制了一个文件。

【问题讨论】:

    标签: c# winforms clipboard


    【解决方案1】:

    我无法确认这是否可行,但我认为您没有理由不能使用更长的实际读取数据并在之后恢复数据的方法来备份数据。

    在这里阅读:http://msdn.microsoft.com/en-us/library/system.windows.forms.idataobject.aspx

    你会做类似(伪代码)的事情

    //Backup
    var lBackup = new Dictionary<string, object>();
    var lDataObject = Clipboard.GetDataObject();
    var lFormats = lDataObject.GetFormats(false);
    foreach(var lFormat in lFormats)
    {
      lBackup.Add(lFormat, lDataObject.GetData(lFormat, false));
    }
    
    //Set test data
    Clipboard.SetText("asd");
    
    //Would be interesting to check the contents of lDataObject here
    
    //Restore data
    foreach(var lFormat in lFormats)
    {
      lDataObject.SetData(lBackup[lFormat]);
    }
    //This might be unnecessary
    Clipboard.SetDataObject(lDataObject);
    

    【讨论】:

      【解决方案2】:

      重置剪贴板后您的应用程序是否退出?

      假设它是一个 Win Form 应用程序。 (虽然不确定它在 wpf 中是如何工作的) 您可以使用 Clipboard.SetDataObject 的其他重载版本之一

      public static void SetDataObject(object data, bool copy) 
      

      即使在您的应用退出后也会保留数据。

      例如:在您的情况下,您可以在删除文本内容后致电Clipboard.SetDataObject(iDataObject, true);

      编辑:2

      我可以通过 Clipboard.cs .NET Frameword 4 / VS 2010 获取源步骤。 从此处http://referencesource.microsoft.com/netframework.aspx 下载 .NET Framework 4。 请按照以下步骤操作,如果它要求提供源(Clipboard.cs),它将位于安装目录的 Source 子目录中。

      编辑:1

      不知道为什么相同的代码不起作用。 不能是安全/权限问题,因为代码不会像你说的那样抛出异常。

      还有另一种方法 - 源代码进入框架代码 - Clipboard.cs 基于 VS 版本和 .NET 框架,它可能会有所不同(我无法获得 .NET 4 的源代码步进工作,因为信息是具有源代码支持的符号尚未发布)。我正在通过从here(.NET 版本 4)手动下载来试试运气

      如果您运行的是 VS 2008 和更早版本的 .NET,那么以下步骤应该适合您。

      更多详情请联系here。对于 .NET Framework 4 - here

      【讨论】:

      • 问题在于它与应用程序重置无关,因为我的应用程序应该工作很多时间,而用户不希望他的剪贴板改变。这里没有重置。我需要在应用程序仍处于打开状态时进行备份和恢复。
      • 在任何一种情况下,上面粘贴的代码都应该仍然有效。它会抛出任何异常吗?
      【解决方案3】:

      这是无法做到的。您无法备份/恢复剪贴板而不会造成意外后果。 请参阅我关于类似问题的帖子。我的答案是以“尝试这样做是愚蠢的”开头的。

      How do I backup and restore the system clipboard in C#?

      此外,我怀疑您想要备份/恢复剪贴板的动机是因为您想在未经用户知情或同意的情况下将其用作移动数据的拐杖。请阅读: http://www.clipboardextender.com/developing-clipboard-aware-programs-for-windows/common-general-clipboard-mistakeshttp://www.flounder.com/badprogram.htm#clipboard

      最后,请阅读并理解这句话:

      “程序不应在没有用户明确指示的情况下将数据从剪贴板传输到我们的外部。” — Charles Petzold,Windows 3.1 编程,微软出版社,1992 年

      【讨论】:

      • 这一切都是正确的,但您可能从未使用过 PowerPoint API。使用剪贴板是将形状/幻灯片/笔记从一个演示文稿复制到另一个演示文稿的唯一方法。见stackoverflow.com/questions/5073988/…stackoverflow.com/questions/5740749/…stackoverflow.com/questions/15043767/…
      • 甚至是老式的 Word CommandBarButton 自定义图标...您必须将图像复制到剪贴板,然后使用 PasteFace()
      • 这也是从 BrowserControl 获取图片的唯一方式。
      • 不反对 Petzold(这是个好建议,但有时这是你唯一的选择)——我只是想指出剪贴板数据对象应该是可序列化的——曾经有一个工具可以附带窗口,可让您将剪贴板 sn-ps 保存到桌面,并在以后恢复它们;它保留了实际的底层数据对象,而不仅仅是格式的副本。 -- 我还使用了保存剪贴板历史记录并让您稍后恢复这些项目的 Windows 程序 -- 所以,似乎肯定有一种坚如磐石的方法可以做到这一点,我们只是想知道如何。跨度>
      【解决方案4】:

      我测试了 Lukas 的伪代码,发现它并不总是有效,这在我的所有测试中都有效:

      // Backup clipboard 
      lBackup = new Dictionary<string, object>();
      lDataObject = Clipboard.GetDataObject();
      lFormats = lDataObject.GetFormats(false);
      foreach (var lFormat in lFormats)
      {
          lBackup.Add(lFormat, lDataObject.GetData(lFormat, false));
      }
      
      //Set test data
      Clipboard.SetText("asd");
      
      //Restore clipboard
      lDataObject = new DataObject();
      foreach (var lFormat in lFormats)
      {
          lDataObject.SetData(lFormat, lBackup[lFormat]);
      }
      //This might be unnecessary
      Clipboard.SetDataObject(lDataObject);
      

      【讨论】:

        【解决方案5】:

        我在这方面取得了成功。

        ...在一定程度上。

        我目前正在尝试复制和恢复不同大小的位图。 我可以成功复制和恢复小尺寸的位图。

        然后,我尝试对一个庞大的 Excel 工作表执行相同的操作(正如事先警告的 Chris Thornton 所建议的那样),该工作表包含数千个单元格数据以及图表上的两组数据,位于同一个工作表上。

        我发现数据复制和恢复没有问题。在这种情况下它失败的地方是允许带有工作表副本的 2-set 图表。

        如果你们中的任何人在复制和恢复位图时遇到问题,让我建议对我有用的方法:尝试恢复剪贴板时,以相反的顺序遍历格式列表并以这种方式设置每个数据对象。 (即,似乎剪贴板必须以与其复制相反的顺序设置)

        关于庞大的 Excel 工作表和随附图表的情况,我还遇到了另一个绊脚石:我无法成功复制格式为“元数据文件”的数据对象。这可能是复制/恢复在这种情况下不起作用的原因。

        大约两周前,我做到了这一点,并提出了更紧迫的问题。

        我想把它放在那里,让其他人尝试做同样的事情,似乎可以做到。 (计算机科学可以做任何事情。任何事情。)

        【讨论】:

          【解决方案6】:

          我编译了这段代码,它似乎对我有用。我通过与 json 之间的转换来坚持。 (注意。它不会做蒸汽,所以如果你需要它就适应)

          using Newtonsoft.Json;
          using System;
          using System.Collections.Generic;
          using System.Linq;
          using System.Threading;
          
          namespace Clipboard
          {
              class Program
              {
                  static void Main(string[] args)
                  {                                    
                      Execute(() =>
                      {
                          var backup = Backup();
                          System.Windows.Forms.Clipboard.SetText("text"); //just to change clipboard
                          Restore(backup);
                      });                
                  }
          
                  private static void Execute(Action action)
                  {
                      var thread = new Thread(() => action());
                      thread.SetApartmentState(ApartmentState.STA);
                      thread.Start();
                      thread.Join();
                  }
          
                  private static List<ClipboardItem> Backup()
                  {
                      var backup = new List<ClipboardItem>();
                      var data = System.Windows.Forms.Clipboard.GetDataObject();
                      System.Windows.Forms.Clipboard.SetDataObject(data, copy: true); //This seems to be needed to be able to serialize data later.
                      data = System.Windows.Forms.Clipboard.GetDataObject();
                      var formats = data.GetFormats(false).ToList();
                      formats.ForEach(f =>
                      {
                          if (data.GetData(f, false) != null && !(data.GetData(f, false) is Stream))
                          {                    
                              backup.Add(new ClipboardItem()
                              {
                                  Format = f,
                                  ObjectType = data.GetData(f, false).GetType(),
                                  ObjectJson = JsonConvert.SerializeObject(data.GetData(f, false))
                              });
                          }                
                      });            
                      return backup;
                  }
          
                  private static void Restore(List<ClipboardItem> backup)
                  {
                      var data = new System.Windows.Forms.DataObject();
                      backup.ForEach(item =>
                      {               
                          data.SetData(item.Format, JsonConvert.DeserializeObject(item.ObjectJson, item.ObjectType));
                      });
                      System.Windows.Forms.Clipboard.SetDataObject(data, copy: true);
                  }
              }    
          
              public class ClipboardItem
              {
                  public string Format { get; set; }
                  public Type ObjectType { get; set; }
                  public string ObjectJson { get; set; }
              }
          }
          

          【讨论】:

            猜你喜欢
            • 2011-02-04
            • 2011-11-25
            • 2016-08-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-01-14
            • 2011-07-02
            相关资源
            最近更新 更多