2009-05-22 10 views

Respuesta

283

Puede usar System.Windows.Forms.Clipboard.SetText(...).

+10

Esto es para WinForms; para WPF, ver la respuesta de Jeff Moser (actualmente 2 abajo). –

+2

@DannyBeckett Ahora solo _1_ abajo. –

+4

Para las aplicaciones de consola, deberá decorar el principal con el atributo [STAThread] –

18

WPF: System.Windows.Clipboard (PresentationCore.dll)

Winforms: System.Windows.Forms.Clipboard

Ambos tienen un método estático SetText.

+0

Gracias por la inclusión de la referencia PresentationCore.dll. No se incluye por defecto en la aplicación de consola – xtreampb

58

Ojalá llamar a SetText fuera así de fácil, pero hay bastantes problemas con los que tienes que lidiar. Debe asegurarse de que el subproceso que está llamando se esté ejecutando en STA. A veces puede fallar con un error de acceso denegado y luego funcionar sin problemas segundos después, algo que tiene que ver con los problemas de sincronización COM en el portapapeles. Y si se accede a su aplicación a través de Escritorio remoto, el acceso al portapapeles es incompleto. Utilizamos un método centralizado para manejar todos los escenarios de tesis en lugar de llamar directamente al SetText.

@Stecy: Aquí está nuestro código centralizada:

La clase StaHelper simplemente ejecuta algún código arbitrario en un hilo en el hilo controlado único (STA) - requerido por el portapapeles.

abstract class StaHelper 
{ 
    readonly ManualResetEvent _complete = new ManualResetEvent(false);  

    public void Go() 
    { 
     var thread = new Thread(new ThreadStart(DoWork)) 
     { 
      IsBackground = true, 
     } 
     thread.SetApartmentState(ApartmentState.STA); 
     thread.Start(); 
    } 

    // Thread entry method 
    private void DoWork() 
    { 
     try 
     { 
      _complete.Reset(); 
      Work(); 
     } 
     catch(Exception ex) 
     { 
      if(DontRetryWorkOnFailed) 
       throw; 
      else 
      { 
       try 
       { 
        Thread.Sleep(1000); 
        Work(); 
       } 
       catch 
       { 
        // ex from first exception 
        LogAndShowMessage(ex); 
       } 
      } 
     } 
     finally 
     { 
      _complete.Set(); 
     } 
    } 

    public bool DontRetryWorkOnFailed{ get; set; } 

    // Implemented in base class to do actual work. 
    protected abstract void Work(); 
} 

Luego tenemos una clase específica para configurar el texto en el portapapeles. Es necesario crear manualmente un DataObject en algunos casos extremos en algunas versiones de Windows/.NET. No recuerdo los escenarios exactos ahora y puede que no se requiera en .NET 3.5.

class SetClipboardHelper : StaHelper 
{ 
    readonly string _format; 
    readonly object _data; 

    public SetClipboardHelper(string format, object data) 
    { 
     _format = format; 
     _data = data; 
    } 

    protected override void Work() 
    { 
     var obj = new System.Windows.Forms.DataObject(
      _format, 
      _data 
     ); 

     Clipboard.SetDataObject(obj, true); 
    } 
} 

uso es el siguiente:

new SetClipboardHelper(DataFormats.Text, "See, I'm on the clipboard").Go(); 
+3

+1, he experimentado al menos algunos de estos problemas. Me ha funcionado bien si envuelvo el acceso al portapapeles en try {...} catch (System.Runtime.InteropServices.ExternalException) {}. – Joe

+1

@Paul, ¿sería tan amable de explicar su método centralizado? –

+2

Esta respuesta merece mucho más votos favorables de los que tiene. Además, debe hacer una pregunta autoconfigurada, algo así como "Cómo ejecutar el código STA en un contexto que no sea STA" – Sidney

4

En las formas de Windows, si la cadena está en un cuadro de texto, puede utilizar fácilmente esta:

textBoxcsharp.SelectAll(); 
textBoxcsharp.Copy(); 
textBoxcsharp.DeselectAll(); 
+1

no necesita ingresar todos los elementos selectos y selectos. Solo tiene que poner esto en: 'textBox1.Copy();' – Dozer789

+1

En realidad, usted necesita la basura SelectAll() y DeselectAll(). Según https://msdn.microsoft.com/en-us/library/system.windows.forms.textboxbase.copy(v=vs.120).aspx, lo que se copia en el portapapeles es ** seleccionado actualmente ** texto. –

+2

necesita poner SelectAll(), de lo contrario, no funciona, acabo de [intenté en esta aplicación inútil] (https://github.com/Magneticdud/Paginatore/commit/5b58a89bf947c1be345861e2adbadf3270ad88f7). Sin embargo, no es necesario utilizar DeselectAll() en las aplicaciones WPF. –

8

El uso de la solución mostró en este pregunta, System.Windows.Forms.Clipboard.SetText(...), resultados en la excepción:

hilo actual se debe establecer en el modo de un solo piso hilo (STA) antes de llamadas OLE se pueden hacer

Para evitar esto, se puede añadir el atributo:

[STAThread] 

a

static void Main(string[] args) 
15

Esto funciona para mí:

Quiere hacer:

System.Windows.Forms.Clipboard.SetText("String to be copied to Clipboard"); 

Pero provoca un error que indica que debe estar en un solo hilo de ApartmentState.STA.

Así que hagámoslo correr en tal hilo. El código para ello:

public void somethingToRunInThread() 
{ 
    System.Windows.Forms.Clipboard.SetText("String to be copied to Clipboard"); 
} 

protected void copy_to_clipboard() 
{ 
    Thread clipboardThread = new Thread(somethingToRunInThread); 
    clipboardThread.SetApartmentState(ApartmentState.STA); 
    clipboardThread.IsBackground = false; 
    clipboardThread.Start(); 
} 

Después de llamar copy_to_clipboard(), la cadena se copia en el portapapeles, por lo que se puede pegar o Ctrl + V y volver a la cadena como cadena que se copia en el portapapeles.

+0

Justo en el dinero. ¡Gracias! – CodeBreaker

0

Use try - catch, incluso si tiene un error, seguirá copiando.

Try 
    Clipboard.SetText("copy me to clipboard") 
Catch ex As Exception 

End Try 

Si utiliza un cuadro de mensaje para capturar la excepción, se le mostrará error, pero el valor sigue siendo copiado al portapapeles.

Cuestiones relacionadas