剪贴板复制两次

时间:2017-03-04 16:56:33

标签: c# winforms clipboard clipboarddata

Short Screen-Cast explaining the problem

我正在制作剪贴板程序,可让您查看剪贴板中的内容。

看起来像这样: enter image description here

它似乎可以在飞行中进行精细复制。

问题是我希望能够在剪贴板中返回之前的img / txt并使用它 - 当我使用复选标记按钮时。

它有效,唯一的问题是它将它复制两次到我使用的图像列表/列表框中。当我初始化列表框/图片框时也会发生这种情况。

以下是代码:

namespace Clipboard_Wizard
{
public partial class FormMain : Form
{
    //register the program in the clipboard viewer chain
    [DllImport("User32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);

    [DllImport("User32.dll", CharSet = CharSet.Auto)]
    public static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);

    private const int WM_DRAWCLIPBOARD = 0x0308;        // WM_DRAWCLIPBOARD message
    private IntPtr _clipboardViewerNext;                // Our variable that will hold the value to identify the next window in the clipboard viewer chain

    private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
    {
        ChangeClipboardChain(this.Handle, _clipboardViewerNext);        // Removes our from the chain of clipboard viewers when the form closes.
    }

    List<Image> img = new List<Image>();
    int ImgCount = 0;
    int ImgIndex = -1;
    Image tmp;

    public FormMain()
    {
        InitializeComponent();

        _clipboardViewerNext = SetClipboardViewer(this.Handle);      // Adds our form to the chain of clipboard viewers.

        //set listbox/picturebox to whatever already on clipboard
        if (Clipboard.ContainsImage())
        {
            tmp = Clipboard.GetImage();
            pictureBox1.Image = tmp;
            img.Add(tmp);
            ImgCount++;
            ImgIndex++;
            btnSlctImg.Enabled = true;
            label3.Text = "Image 1 / 1";
        }
        else if (Clipboard.ContainsText())
        {
            listBox1.Items.Add(Clipboard.GetText());
        }
    }

    // clears everything from the form and the clipboard
    private void btnClear_Click(object sender, EventArgs e)
    {
        Clipboard.Clear();
        listBox1.Items.Clear();
        img.Clear();
        pictureBox1.Image = null;
        ImgCount = 0;
        ImgIndex = -1;
        btnSlctImg.Enabled = false;
    }

    private void btnUpdate_Click(object sender, EventArgs e)
    {
        /*if (Clipboard.ContainsImage())
            {
                tmp = Clipboard.GetImage();
                pictureBox1.Image = tmp;
                img.Add(tmp);
                ImgCount++;
                ImgIndex = ImgCount - 1;  

            }
            else if (Clipboard.ContainsText())
            {
                listBox1.Items.Add(Clipboard.GetText());
                listBox1.TopIndex = listBox1.Items.Count - 1;
            }*/
    }



    private void btnUp_Click(object sender, EventArgs e)
    {
        if(ImgIndex == -1)
        {
            MessageBox.Show("No image.");
        }
        else if (ImgIndex < ImgCount - 1)
        {
            ImgIndex++;
            pictureBox1.Image = img[ImgIndex];
            label3.Text = "Image " + (ImgIndex + 1).ToString() + " / " + ImgCount.ToString() ;
        }
        else
        {
            MessageBox.Show("This is the last image.");
        }
    }

    private void btnDown_Click(object sender, EventArgs e)
    {
        if(ImgIndex == -1)
        {
            MessageBox.Show("No image.");
        }
        else if (ImgIndex > 0)
        {
            ImgIndex--;
            pictureBox1.Image = img[ImgIndex];
            label3.Text = "Image " + (ImgIndex + 1).ToString() + " / " + ImgCount.ToString();
        }
        else
        {
            MessageBox.Show("This is the first image.");
        }
    }

    private void btnDeselect_Click(object sender, EventArgs e)
    {
        listBox1.SelectedIndex = -1;
    }

    //sets clipboard to selected txt from listbox
    private void btnSlct_Click(object sender, EventArgs e)
    {
        string slctTxt = listBox1.SelectedItem.ToString();
        if (slctTxt != null || slctTxt != "")
        {
            Clipboard.SetText(slctTxt);
        }
    }

    //sets clipboard to selected image
    private void btnSlctImg_Click(object sender, EventArgs e)
    {
        Image slctImg = pictureBox1.Image;
        if (slctImg != null)
        {
            Clipboard.SetImage(slctImg); 
        }

    }

    private void listBox1_SelectedIndexChanged_1(object sender, EventArgs e)
    {
        if (listBox1.SelectedIndex != -1)
        {
            btnSlctTxt.Enabled = true;
        }
        else
        {
            btnSlctTxt.Enabled = false;
        }
    }

    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);    // Process the message 

        if (m.Msg == WM_DRAWCLIPBOARD)
        {
            //btnUpdate.PerformClick();

            IDataObject iData = Clipboard.GetDataObject();      // Clipboard's data

            if (iData.GetDataPresent(DataFormats.Text))
            {
                string text = (string)iData.GetData(DataFormats.Text);      // Clipboard text
                listBox1.Items.Add(text);
                listBox1.TopIndex = listBox1.Items.Count - 1;
            }
            else if (iData.GetDataPresent(DataFormats.Bitmap))
            {
                tmp = (Bitmap)iData.GetData(DataFormats.Bitmap);   // Clipboard image
                pictureBox1.Image = tmp;
                img.Add(tmp);
                ImgCount++;
                ImgIndex = ImgCount - 1;
                label3.Text = "Image " + ImgCount.ToString() + " / " + ImgCount.ToString();
                btnSlctImg.Enabled = true;  
            }
        }
    }

}
}

更新:似乎问题出现在我调用Clipboard.SetImage(...)Clipboard.SetText(...)时 - 它会执行两次。尽管如此,仍然不明白为什么。

2 个答案:

答案 0 :(得分:1)

您已定义WndProc捕捉对剪贴板的更改,并将内容添加到列表中。

btnSlctImg_Click中执行此操作:

if (slctImg != null)  { Clipboard.SetImage(slctImg);  }

因此,当然剪贴板 已更改,WndProc会被触发,当前所选图像会再次添加到您拥有的列表中。

为避免这种情况,您可能需要测试列表以查看图像或文本是否已在列表中。对于文本来说,这是微不足道的,但对于图像,这不是简单的。您可能必须创建和存储指纹以确定图像是否已存在于列表中。

Here is a post,其中包含为图像创建MD5哈希的示例。

更简单的技巧将是btnSlctImg_ClickClipboard.SetImage之前设置的标记,并在{{1}中进行测试和清除}}。您仍然可以获得重复项,但前提是该程序的用户外部复制了相同的数据。

答案 1 :(得分:-1)

前段时间我写了一个剪贴板工具并将其发布在CodeProject ClipSpy+

我认为它可以帮助你做你正在做的事情!