【问题标题】:Clipboard.GetText returns null (empty string)Clipboard.GetText 返回 null(空字符串)
【发布时间】:2021-02-01 16:17:21
【问题描述】:

我的剪贴板中填充了文本,但是当我运行时

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

我得到一个空字符串。我玩过各种形式的电话,包括:

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

但结果相同。

我是否遗漏了一些明显的东西?

【问题讨论】:

  • 你是如何将数据放入剪贴板的?
  • 剪贴板上的数据是“文本”而不​​是图形、音频或其他数据吗?
  • Null 与空字符串有很大不同。我不确定为什么“null”是您问题的一部分。它只会增加混乱和错误信息。

标签: c# .net


【解决方案1】:

您只能从 STA 线程访问剪贴板。 Rick Brewster 在 Paint.NET 中对常规的 Edit->Paste 命令进行了一些重构,从而遇到了这个问题。

代码:

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

代码来自 Rick。 http://forums.getpaint.net/index.php?/topic/13712-/page__view__findpost__p__226140

更新Jason Heine 提出了在delegate 之后添加() 以修复模棱两可的方法错误的好方法。

【讨论】:

  • 不确定其他框架,但在.net 4.0中,delegate后面需要有(),否则会出现模棱两可的方法错误。
  • 我们应该添加一些锁定吗?
  • 很好的答案,虽然在我的情况下,我只是有一个 WinForms,我删除了 Main 上的 [STAThread] 属性,所以我只需要把它放回去。
  • 您好,我发现有时剪贴板内容在 staThread.Join() 返回后无法立即使用。例如,如果我尝试使用 idat,我会得到一个旧值或 null 等;但是,如果我在尝试访问变量之前添加 1 秒睡眠,它就可以工作。有什么建议为什么会出现这种情况?我要提出一个新问题吗?如果答案意味着我们需要在访问变量以进行可靠读取之前睡眠,我认为这与此处相关。
【解决方案2】:

老实说,我不知道什么是 STA 线程,但在简单的项目中,在 Main 方法之前添加 [STAThread] 可能会解决问题:

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

它对我有用,所以我不质疑这个方法;)


有关[STAThread] 装饰器的更多信息请参见博文Why is STAThread required?

【讨论】:

  • 天哪,这对我帮助很大!非常感谢!
  • 完美的快速控制台应用程序。
【解决方案3】:

我已经写了这个类,它可以工作,做同样的事情,只需添加你需要的方法就可以轻松改进

    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

这是 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;
}
}

您可以简单地使用它: VB.net:

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

Csharp:

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

【讨论】:

    【解决方案4】:

    BoltBait 的代码不适用于 IDataObject,因为数据对象在线程外丢失了信息。一切正常,如果 IDataObject 仅在这样的线程内使用:

    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
    

    【讨论】:

      【解决方案5】:

      这是一个线程问题。我们必须获得正确的线程并通过委托执行。

      我通过每 500 毫秒运行一次的计时器更新我的属性。代码如下:

          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
              { }
          }
      

      此外,我已经使用 ClipboardString 创建了一个适当的 DependencyProperty:

          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); }
          }
      

      假设我的控件或窗口x:Name="_this"

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

      【讨论】:

      • 这是对原始问题的另一个答案吗?如果是这样,那么它提供了什么新功能?
      【解决方案6】:

      由于某种原因,BoltBait 的代码不能正常工作(即使在 staThread.Join() 之后,idat 仍然为空)。我只是在 staThread 委托中执行 Clipboard.GetText() 而不是 Clipboard.GetDataObject() 并且效果很好。

      谢谢 - 你的代码 sn-p 让我成功了 99% :)

      【讨论】:

      • 嗨乔纳森 - 我看到了完全相同的事情,也做了同样的事情。
      猜你喜欢
      • 1970-01-01
      • 2012-09-18
      • 1970-01-01
      • 1970-01-01
      • 2012-10-09
      • 2020-09-28
      • 2017-03-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多