¿Cómo copio el contenido de una cadena al portapapeles en C#? [duplicar]
Si tengo algo de texto en una Cadena, ¿cómo puedo copiarlo al portapapeles para que el usuario pueda pegarlo en otra ventana (por ejemplo, desde mi aplicación al Bloc de notas)?
Puedes usar System.Windows.Forms.Clipboard.SetText(...)
.
System.Windows.Forms.Clipboard.SetText
(Formularios de Windows) o System.Windows.Clipboard.SetText
(WPF)
Ojalá llamar SetText
fuera así de fácil, pero hay bastantes problemas con los que tienes que lidiar. Debe asegurarse de que el hilo al que lo está llamando se esté ejecutando en STA. A veces puede fallar con un error de acceso denegado y luego funcionar segundos después sin problemas, 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. Usamos un método centralizado para manejar todos estos escenarios en lugar de llamar SetText
directamente.
@Stecy: Aquí está nuestro código centralizado:
La clase StaHelper simplemente ejecuta algún código arbitrario en un subproceso en el Single Thread Apartment (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 texto en el portapapeles. DataObject
Es necesario crear un archivo manualmente en algunos casos extremos en algunas versiones de Windows/.NET. No recuerdo los escenarios exactos ahora y es posible que no sea necesario 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 );
}
}
El uso se ve así:
new SetClipboardHelper( DataFormats.Text, "See, I'm on the clipboard" ).Go();
WPF: System.Windows.Clipboard
(PresentaciónCore.dll)
Formas de Win:System.Windows.Forms.Clipboard
Ambos tienen un SetText
método estático.
Esto funciona para mí:
Quieres hacer:
System.Windows.Forms.Clipboard.SetText("String to be copied to Clipboard");
Pero provoca un error que indica que debe estar en un único hilo de ApartmentState.STA.
Así que hagamos que se ejecute en ese 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 puede Pegar o Ctrl+ Vy recuperar la cadena como Cadena para copiarla en el portapapeles .