2009-02-06 24 views
36

Mi portapapeles se rellena con el texto, pero cuando corroClipboard.GetText devuelve un valor nulo (cadena vacía)

string clipboardData = Clipboard.GetText(System.Windows.Forms.TextDataFormat.Text); 

que volver una cadena vacía. He jugado con varias formas de la llamada incluyendo:

string clipboardData = Clipboard.GetText(); 
string clipboardData = Clipboard.GetText(System.Windows.Forms.TextDataFormat.UnicodeText); 

Pero con el mismo resultado.

¿Me falta algo obvio?

+0

¿Cómo está poniendo datos en el portapapeles? –

+0

¿Los datos que se encuentran en el portapapeles son "texto" y no gráficos, audio u otros? – JMD

Respuesta

45

Solo puede acceder al portapapeles desde un hilo STA. Rick Brewster se topó con esto con algunas refactorizaciones del comando regular Editar-> Pegar, en Paint.NET.

Código:

IDataObject idat = null; 
Exception threadEx = null; 
Thread staThread = new Thread(
    delegate() 
    { 
     try 
     { 
      idat = Clipboard.GetDataObject(); 
     } 

     catch (Exception ex) 
     { 
      threadEx = ex;    
     } 
    }); 
staThread.SetApartmentState(ApartmentState.STA); 
staThread.Start(); 
staThread.Join(); 
// at this point either you have clipboard data or an exception 

Código es de Rick. http://forums.getpaint.net/index.php?/topic/13712-/page__view__findpost__p__226140

actualización: Jason Heine hizo un buen punto de añadir () después delegate para corregir el error método ambiguo.

+5

no estoy seguro acerca de otros marcos, pero en .net 4.0 el delegado necesita tener() después de eso, de lo contrario se obtiene un error de método ambiguo. – CodeLikeBeaker

+0

¿Deberíamos agregar algo de bloqueo? – Toto

+0

Buena respuesta, aunque en mi caso fue solo que tenía un WinForms donde había eliminado el atributo [STAThread] en Main, así que solo tuve que volver a colocarlo. –

0

Por alguna razón, el código de BoltBait no funcionó del todo (aún era nulo incluso después de staThread.Join()). Acabo de hacer Clipboard.GetText() dentro del delegado staThread en lugar de Clipboard.GetDataObject() y eso funcionó bien.

Gracias sin embargo - el fragmento de código me consiguieron un 99% allí :)

+0

Impresionante. Me alegra que lo hayas hecho funcionar. – BoltBait

+0

Hola Jonathan: vi exactamente lo mismo e hice lo mismo también. – Matt

9

he escrito esta clase, funciona, y hacer lo mismo y se pueden mejorar fácilmente con sólo añadir el método que necesita

Private Class ClipboardAsync 

    Private _GetText As String 
    Private Sub _thGetText(ByVal format As Object) 
     Try 
      If format Is Nothing Then 
       _GetText = Clipboard.GetText() 
      Else 
       _GetText = Clipboard.GetText(DirectCast(format, TextDataFormat)) 
      End If 

     Catch ex As Exception 
      _GetText = String.Empty 
     End Try 
    End Sub 
    Public Function GetText() As String 
     Dim instance As New ClipboardAsync 
     Dim staThread As New Thread(AddressOf instance._thGetText) 
     staThread.SetApartmentState(ApartmentState.STA) 
     staThread.Start() 
     staThread.Join() 
     Return instance._GetText 
    End Function 
    Public Function GetText(ByVal format As TextDataFormat) As String 
     Dim instance As New ClipboardAsync 
     Dim staThread As New Thread(AddressOf instance._thGetText) 
     staThread.SetApartmentState(ApartmentState.STA) 
     staThread.Start(format) 
     staThread.Join() 
     Return instance._GetText 
    End Function 

    Private _ContainsText As Boolean 
    Private Sub _thContainsText(ByVal format As Object) 
     Try 
      If format Is Nothing Then 
       _ContainsText = Clipboard.ContainsText() 
      Else 
       _ContainsText = Clipboard.ContainsText(DirectCast(format, TextDataFormat)) 
      End If 
     Catch ex As Exception 
      _ContainsText = False 
     End Try 
    End Sub 
    Public Function ContainsText() As Boolean 
     Dim instance As New ClipboardAsync 
     Dim staThread As New Thread(AddressOf instance._thContainsFileDropList) 
     staThread.SetApartmentState(ApartmentState.STA) 
     staThread.Start() 
     staThread.Join() 
     Return instance._ContainsText 
    End Function 
    Public Function ContainsText(ByVal format As Object) As Boolean 
     Dim instance As New ClipboardAsync 
     Dim staThread As New Thread(AddressOf instance._thContainsFileDropList) 
     staThread.SetApartmentState(ApartmentState.STA) 
     staThread.Start(format) 
     staThread.Join() 
     Return instance._ContainsText 
    End Function 

    Private _ContainsFileDropList As Boolean 
    Private Sub _thContainsFileDropList(ByVal format As Object) 
     Try 
      _ContainsFileDropList = Clipboard.ContainsFileDropList 
     Catch ex As Exception 
      _ContainsFileDropList = False 
     End Try 
    End Sub 
    Public Function ContainsFileDropList() As Boolean 
     Dim instance As New ClipboardAsync 
     Dim staThread As New Thread(AddressOf instance._thContainsFileDropList) 
     staThread.SetApartmentState(ApartmentState.STA) 
     staThread.Start() 
     staThread.Join() 
     Return instance._ContainsFileDropList 
    End Function 

    Private _GetFileDropList As Specialized.StringCollection 
    Private Sub _thGetFileDropList() 
     Try 
      _GetFileDropList = Clipboard.GetFileDropList 
     Catch ex As Exception 
      _GetFileDropList = Nothing 
     End Try 
    End Sub 
    Public Function GetFileDropList() As Specialized.StringCollection 
     Dim instance As New ClipboardAsync 
     Dim staThread As New Thread(AddressOf instance._thGetFileDropList) 
     staThread.SetApartmentState(ApartmentState.STA) 
     staThread.Start() 
     staThread.Join() 
     Return instance._GetFileDropList 
    End Function 
End Class 

Aquí está la versión CSharp:

private class ClipboardAsync 
{ 

private string _GetText; 
private void _thGetText(object format) 
{ 
    try { 
     if (format == null) { 
      _GetText = Clipboard.GetText(); 
     } 
     else { 
      _GetText = Clipboard.GetText((TextDataFormat)format); 

     } 
    } 
    catch (Exception ex) { 
     //Throw ex 
     _GetText = string.Empty; 
    } 
} 
public string GetText() 
{ 
    ClipboardAsync instance = new ClipboardAsync(); 
    Thread staThread = new Thread(instance._thGetText); 
    staThread.SetApartmentState(ApartmentState.STA); 
    staThread.Start(); 
    staThread.Join(); 
    return instance._GetText; 
} 
public string GetText(TextDataFormat format) 
{ 
    ClipboardAsync instance = new ClipboardAsync(); 
    Thread staThread = new Thread(instance._thGetText); 
    staThread.SetApartmentState(ApartmentState.STA); 
    staThread.Start(format); 
    staThread.Join(); 
    return instance._GetText; 
} 

private bool _ContainsText; 
private void _thContainsText(object format) 
{ 
    try { 
     if (format == null) { 
      _ContainsText = Clipboard.ContainsText(); 
     } 
     else { 
      _ContainsText = Clipboard.ContainsText((TextDataFormat)format); 
     } 
    } 
    catch (Exception ex) { 
     //Throw ex 
     _ContainsText = false; 
    } 
} 
public bool ContainsText() 
{ 
    ClipboardAsync instance = new ClipboardAsync(); 
    Thread staThread = new Thread(instance._thContainsFileDropList); 
    staThread.SetApartmentState(ApartmentState.STA); 
    staThread.Start(); 
    staThread.Join(); 
    return instance._ContainsText; 
} 
public bool ContainsText(object format) 
{ 
    ClipboardAsync instance = new ClipboardAsync(); 
    Thread staThread = new Thread(instance._thContainsFileDropList); 
    staThread.SetApartmentState(ApartmentState.STA); 
    staThread.Start(format); 
    staThread.Join(); 
    return instance._ContainsText; 
} 

private bool _ContainsFileDropList; 
private void _thContainsFileDropList(object format) 
{ 
    try { 
     _ContainsFileDropList = Clipboard.ContainsFileDropList; 
    } 
    catch (Exception ex) { 
     //Throw ex 
     _ContainsFileDropList = false; 
    } 
} 
public bool ContainsFileDropList() 
{ 
    ClipboardAsync instance = new ClipboardAsync(); 
    Thread staThread = new Thread(instance._thContainsFileDropList); 
    staThread.SetApartmentState(ApartmentState.STA); 
    staThread.Start(); 
    staThread.Join(); 
    return instance._ContainsFileDropList; 
} 

private Specialized.StringCollection _GetFileDropList; 
private void _thGetFileDropList() 
{ 
    try { 
     _GetFileDropList = Clipboard.GetFileDropList; 
    } 
    catch (Exception ex) { 
     //Throw ex 
     _GetFileDropList = null; 
    } 
} 
public Specialized.StringCollection GetFileDropList() 
{ 
    ClipboardAsync instance = new ClipboardAsync(); 
    Thread staThread = new Thread(instance._thGetFileDropList); 
    staThread.SetApartmentState(ApartmentState.STA); 
    staThread.Start(); 
    staThread.Join(); 
    return instance._GetFileDropList; 
} 
} 

Usted puede utilizar sencilla con: Vb.net:

Dim Clipboard2 As New ClipboardAsync 
MessageBox.Show (Clipboard2.ContainsText()) 

Csharp:

ClipboardAsync Clipboard2 = new ClipboardAsync(); 
MessageBox.Show (Clipboard2.ContainsText()); 
31

Honestamente, no sé lo que es un subproceso STA es, pero en proyectos simples que podría resolver el problema de añadir [STAThread] justo antes de la Main método:

[STAThread] 
static void Main(string[] args) 
{ (...) 

funciona para mí, así que no cuestionan el método;)


Más información sobre el decorador [STAThread] está en la publicación de blog Why is STAThread required?.

+1

¡Oh Dios, esto me ayudó MUCHO! ¡Muchas gracias! – theknut

+0

Perfecto para una aplicación de consola rápida. – Grant

+1

Ojalá pudiera votar una y otra vez. – Max

1

Este es un problema de enhebrado. Tenemos que obtener el hilo correcto y ejecutarlo a través de los delegados.

Estoy actualizando mis propiedades a través de un temporizador que transcurre cada 500 ms.Aquí está el código:

public delegate void ClipboarDelegate(); 

    ClipboarDelegate clipboardDelegate = null; 

    void clipboardTimer_Elapsed(object sender, ElapsedEventArgs e) 
    { 
     if (clipboardDelegate == null) 
      clipboardDelegate = ClipboarDelegateMethod; 

     //Here we get the right thread, most probably the application thread 
     Application.Current.Dispatcher.BeginInvoke(clipboardDelegate); 
    } 

    public void ClipboarDelegateMethod() 
    { 
     try 
     { 
      if (Clipboard.ContainsData(DataFormats.Text)) 
      { 
       //It's important to lock this section 
       lock (ClipboardString) 
       { 
        ClipboardString = Clipboard.GetData(DataFormats.Text) as string; 
       } 
      } 
     } 
     catch 
     { } 
    } 

Por otra parte he hecho un DependencyProperty adecuada con ClipboardString:

public static readonly DependencyProperty ClipboardStringDP = 
     DependencyProperty.Register("ClipboardString", 
            typeof(string), 
            typeof(MainWindow), 
            new UIPropertyMetadata(string.Empty)); 

    public string ClipboardString 
    { 
     get { return (string)this.GetValue(ClipboardStringDP); } 
     set { this.SetValue(ClipboardStringDP, value); } 
    } 

De esta manera se puede enlazar a mi cuadro de texto en XAML asumiendo mi control o ventana x:Name="_this":

<TextBox Name="ClipBoardTextBox" 
     DataContext="{Binding ElementName=_this}" 
     Text="{Binding Path=ClipboardString, Mode=OneWay}"/> 
+0

¿Quiere decir esto como otra respuesta a la pregunta original? Si es así, ¿qué ofrece eso? – ClickRick

5

El código de BoltBait no funcionaba para IDataObject porque el objeto de datos pierde información fuera del hilo. Todo funciona bien, si el objeto IDataObject se usa solo dentro del hilo como este:

IDataObject idat = null; 
Exception threadEx = null; 
String text = ""; 
Thread staThread = new Thread(
    delegate() 
    { 
     try 
     { 
      idat = Clipboard.GetDataObject(); 
      text = idat.GetData(DataFormats.Text) 
     } 

     catch (Exception ex) 
     { 
      threadEx = ex;    
     } 
    }); 
staThread.SetApartmentState(ApartmentState.STA); 
staThread.Start(); 
staThread.Join(); 
// here you can use text, which contains data from clipboard 
Cuestiones relacionadas