0

画像ボックスに画像を保持するアプリケーションがあります。ctrl+C を押すと、画像がクリップボードにコピーされます。スレッドを使用して、実際のクリップボード操作を実行します。

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    if (keyData == (Keys.Control | Keys.C))
    {
        clipboardThread = new Thread(copy_to_clipboard);
        clipboardThread.SetApartmentState(ApartmentState.STA);
        clipboardThread.Start();
        return true;
    }
    return base.ProcessCmdKey(ref msg, keyData);
}

private void copy_to_clipboard()
{
    if (pic_display.Image != null)
    {
        using (MemoryStream stream = new MemoryStream())
        {
            clipboardStatus.Text = "Copying image to clipboard...";
            pic_display.Image.Save(stream, ImageFormat.Png);
            var data = new DataObject("PNG", stream);
            Clipboard.Clear();
            Clipboard.SetDataObject(data, true);
            clipboardStatus.Text = "Copied successfully!";
        }
    }
}

現在、ctrl+C を繰り返し送信すると (例: キーを押したままにする)、新しいスレッドが生成されます。クリップボード スレッドを再利用するようにコードを変更し、現在データをコピーしているかどうかを教えて、まだ動作中に別のコピー コマンドを実行しようとしないようにするにはどうすればよいですか。

アップデート

今それは動作します

バックグラウンドワーカーを使用するように変更しました

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    if (keyData == (Keys.Control | Keys.C))
    {
        if (!backgroundWorker1.IsBusy)
            backgroundWorker1.RunWorkerAsync();
        return true;
    }
    return base.ProcessCmdKey(ref msg, keyData);
}

private void copy_to_clipboard()
{
    using (var stream = new MemoryStream())
    {
        clipboardStatus.Text = "Copying image to clipboard...";
        pic_display.Invoke((Action)(() => {
            if (pic_display.Image != null)
              pic_display.Image.Save(stream, ImageFormat.Png); 
        }));
        if (stream.Position == 0) return; // No image was saved
        var data = new DataObject("PNG", stream);
        BeginInvoke ( (Action) ( ()=> {
            Clipboard.Clear();
            Clipboard.SetDataObject(data, true);
        }
        clipboardStatus.Text = "Copied successfully!";
    }
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    copy_to_clipboard();
}

しかし今、例外が発生します

Clipboard.Clear();

言って

Current thread must be set to single thread apartment (STA) mode before OLE calls can be made. Ensure that your Main function has STAThreadAttribute marked on it.
4

4 に答える 4

1

まず、バックグラウンドスレッドからUIコントロールにアクセスするときに呼び出す必要があります。

private void copy_to_clipboard()
{
    using (var stream = new MemoryStream())
    {
        clipboardStatus.Text = "Copying image to clipboard...";
        pic_display.Invoke((Action)()=> { 
            if (pic_display.Image != null)
              pic_display.Image.Save(stream, ImageFormat.Png); 
        });
        if (stream.Position == 0) return; // No image was saved
        var data = new DataObject("PNG", stream);
        Clipboard.Clear();
        Clipboard.SetDataObject(data, true);
        clipboardStatus.Text = "Copied successfully!";
    }
}

次に、BackgroundWorkerからそれを呼び出します。その多くの例がWebで入手できます。

于 2012-07-31T19:44:47.393 に答える
1

クリック中に保存を実行することをお勧めします。とにかく、UI スレッドで実行する必要があります。InvokeRequired/Invoke; を使用できます。ただし、その保存がいつ UI スレッドを引き継ぐかを制御することはできません。クリック後かなりの時間がかかり、ユーザーを当惑させる可能性があります。または、ユーザーが画像を変更したかもしれません。UIスレッドから時間がかかるのは残念です。ただし、クリックに近いほど、使いやすさの観点からは優れています。その場合、おそらく次のようなものです:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    if (keyData == (Keys.Control | Keys.C))
    {
        if (pic_display.Image != null)
        {
            MemoryStream stream = new MemoryStream())
            clipboardStatus.Text = "Copying image to clipboard...";
            pic_display.Image.Save(stream, ImageFormat.Png);

            clipboardThread = new Thread(copy_to_clipboard);
            clipboardThread.SetApartmentState(ApartmentState.STA);
            clipboardThread.Start(stream);
        }
        return true;
    }
    return base.ProcessCmdKey(ref msg, keyData);
}

private void copy_to_clipboard(object state)
{
    var stream = (Stream) state;
    try
    {
        var data = new DataObject("PNG", stream);
        Clipboard.Clear();
        Clipboard.SetDataObject(data, true);
        BeginInvoke((MethodInvoker) (() => clipboardStatus.Text = "Copied successfully!"));
    }
    finally
    {
        stream.Dispose();
    }
}
于 2012-07-31T20:11:20.833 に答える
0

そのようなことを試してください:

object lockObj = new object();

        private void copy_to_clipboard()
        {
            lock (lockObj)
            {
                if (pictureBox1.Image != null)
                    {
                        using (MemoryStream stream = new MemoryStream())
                        {
                            clipboardStatus.Text = "Copying image to clipboard...";                            
                            pictureBox1.Image.Save(stream, ImageFormat.Png);
                            var data = new DataObject("PNG", stream);
                            Clipboard.Clear();
                            Clipboard.SetDataObject(data, true);                            
                            clipboardStatus.Text = "Copied successfully!";
                        }
                    } 
            }
        }
于 2012-07-31T19:34:38.097 に答える
0

スレッドをメンバーとして保存することはできませんか? 私が質問を誤解していない限り、 Thread.IsAlive はあなたが望むことをします。ただし、上記のポスターのように UI コントロールを変更している場合は、実際に Invoke を使用して、これが UI スレッドで発生することを確認する必要があります。

protected Thread clipboardThread;

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{

if (keyData == (Keys.Control | Keys.C))
{
    if (clipBoardThread == null)
    {
       clipboardThread = new Thread(copy_to_clipboard);
       clipboardThread.SetApartmentState(ApartmentState.STA);
       clipboardThread.IsBackGround = false;
    }
    if (!clipboardThread.IsAlive)
    {
       clipboardThread.Start();
    }
    return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}

private void copy_to_clipboard()
{
if (pic_display.Image != null)
{
    using (MemoryStream stream = new MemoryStream())
    {
        clipboardStatus.Text = "Copying image to clipboard...";
        pic_display.Image.Save(stream, ImageFormat.Png);
        var data = new DataObject("PNG", stream);
        Clipboard.Clear();
        Clipboard.SetDataObject(data, true);
        clipboardStatus.Text = "Copied successfully!";
    }
}
}

于 2012-07-31T19:51:59.620 に答える