使用文本或图像保存原始剪贴板,稍后在 C# 中恢复它

Save original clipboard with text or image and restore it later in C#

我正在尝试创建一个 C# WinForms 剪贴板管理器,它可以记住最后的 X 剪贴板条目,如果它包含图像或文本(不是文件、流或其他花哨的东西)。然后我希望以后能够恢复剪贴板,所以我可以粘贴原始文本或图像。 我的问题是,即使我将剪贴板复制为 IDataObject,之后我也无法恢复它 - 至少不是对所有应用程序都如此?

为了测试它,我创建了这个非常简单的代码:

// Get data object from clipboard 
IDataObject clipboardObject = Clipboard.GetDataObject();

// Set the exact same data object to the clipboard
Clipboard.SetDataObject(clipboardObject);

我为此准备了两个测试用例 - 一个 Wordpad 文件和一个 Word 文件。两者都带有简单格式的文本 - 例如颜色编码或斜体 - 可以看出它不是纯文本。

如果我从 写字板 复制文本,然后再启动我的简单应用程序,那么我可以再次粘贴该文本,格式正确 - 没问题。

Word 中执行相同的操作,然后它会粘贴一些奇怪的东西 - 一个空文件对象或类似的东西!?

Word 的左下角写着:

Double-click or double-tab to Open Microsoft Word Document

它现在似乎将剪贴板视为文件指针或类似的东西?如果我双击该区域,它实际上会打开一个新的 Word 文件!?我不明白?

我已经检查过 C# Backing Up And Restoring Clipboard,我可以承认,谁实际上是相同的,但我也尝试了那里的各种建议,但至少没有一个对我有用?我希望 10 年后可能会有更好的答案? ;-)

仅从对象恢复文本格式也不起作用,因为剪贴板将在它为空时起作用(它不会粘贴任何内容)。

有没有人有恢复剪贴板的经验(在文本和图像方面)?

我的目标是将剪贴板历史保存在例如一个Dictionary然后遍历up/down,这样我就可以恢复我需要的


解决方案

根据下面@Jimi 的评论,这确实解决了我的问题:

// Set the exact same data object to the clipboard
Clipboard.SetDataObject(clipboardObject, true);

据我了解,如果 copy 参数未设置或设置为 false,那么它实际上将引用指针。如果此参数设置为 true,那么它将在剪贴板中设置实际数据,即使我的应用程序存在,数据仍将保留在那里。


更新 - 如何 save/restore 已使用 SetText

放入剪贴板的对象

虽然我已经解决了这个问题的主要问题,但我仍然面临挑战,我认为它也可以在这里解决。我想存储剪贴板对象,以便稍后获取它们 - 可能在 Dictionary 中。然后我创建了这个 PoC,它似乎在很多情况下都有效,但是如果数据以 SetText 的形式存储到剪贴板,那么在恢复和粘贴时它似乎 return 是一个空的剪贴板?

如果您在此处查看此代码,那么我正在恢复我手动设置的剪贴板 - 它不会粘贴任何内容并且剪贴板看起来是空的:

        // Define variables
        Dictionary<int, object> clipboardObjects = new Dictionary<int, object>();
        IDataObject clipboardObject;

        // Get formatted text content from clipboard (copied from Word)
        clipboardObject = Clipboard.GetDataObject();

        // Add clipboard object in the first [0] dictionary
        clipboardObjects.Add(0, clipboardObject);

        // Put new content to the clipboard - just to show we can destroy it before restoring again
        Clipboard.SetText("Test, to alter the clipboard");

        // Add clipboard object in the second [1] dictionary
        clipboardObject = Clipboard.GetDataObject();
        clipboardObjects.Add(1, clipboardObject);

        // Now restore the second [1] clipboard object - which will result in an empty clipboard
        clipboardObject = (IDataObject)clipboardObjects[1];
        Clipboard.SetDataObject(clipboardObject, true);

以上将导致剪贴板空白 - 或者至少不会粘贴任何内容。有趣的是,如果我恢复第一个 [0] 对象(包含格式化文本),那么它会恢复它,我可以很好地粘贴它!?

为什么不能恢复SetText对象?

我的问题是这不起作用,我不知道应用程序如何将数据存储到剪贴板。 SetText 可能是他们存储它的方式。我已经用 SetDataObject 而不是 SetText 测试了它,然后我可以恢复它。

因为没有人回答这个问题,所以我会自己做,因为我根据@Jimi 的评论找到了解决方案。我的回答没有涵盖我 100% 的问题,但它解决了我的问题。我怀疑它是否适用于所有情况,但至少它适用于我对它的基本使用,它只关注剪贴板中的文本和图像。

我已经在 Windows 10 中使用 WordpadWord 测试了以下代码,它可以工作,但当然可以在你的场景中改变或工作不同,但也许它可以为有类似问题的人提供一些提示:-)

该代码将从剪贴板中抓取相关格式(带格式的文本或图像)并将其保存到 DictionaryList。之后你可以对剪贴板做任何你想做的事,稍后你可以再次检索和恢复剪贴板。

using System.Windows.Forms;
using System.Collections.Generic;

// Define variables
int key = 0;
IDataObject clipboardObject;
SortedList<int, Dictionary<string, object>> clipboardOriginals = new SortedList<int, Dictionary<string, object>>(); // can be referred by integer and can contain clipboard objects

// ---------
// Save formatted clipboard to a list of dictionaries

// Get the clipboard object
clipboardObject = Clipboard.GetDataObject();

// Walk through all (relevant) clipboard formats and save them in a new object
var formats = clipboardObject.GetFormats(false);
Dictionary<string, object> clipboardFormats = new Dictionary<string, object>();
foreach (var format in formats)
{
    if (
        format.Contains("Text") ||
        format.Contains("Hyperlink") ||
        format.Contains("Bitmap")
    )
    {
        // Add the clipboard format to the clipboard object
        clipboardFormats.Add(format, clipboardObject.GetData(format));
    }
}

// Save the clipboard formats to the dictionary containing all originals
clipboardOriginals.Add(key, clipboardFormats);

// ---------
// Now do whatever you want with the clipboard
Clipboard.Clear();
Clipboard.SetText("Cleared");

// ---------
// Restore the (semi) original clipboard - at least the relevant formats we have saved

DataObject data = new DataObject();
foreach (KeyValuePair<string, object> kvp in clipboardOriginals[key])
{
    if (kvp.Value != null)
    {
        data.SetData(kvp.Key, kvp.Value);
    }
}

// Copy the saved formats to the clipboard
Clipboard.SetDataObject(data, true);

// Try now to paste the clipboard - it should contain the original formatting (hopefully)? :-)

这可能根本不是防弹的,但到目前为止它似乎对我和我的用法有用。