C# Clipboard.GetText 返回 null(空字符串)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/518701/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 06:30:39  来源:igfitidea点击:

Clipboard.GetText returns null (empty string)

c#.net

提问by Matthew

My clipboard is populated with text, but when I run

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

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

I get back an empty string. I've toyed with various forms of the call including:

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

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

But with the same result.

但结果相同。

Am I missing something obvious?

我错过了一些明显的东西吗?

采纳答案by BoltBait

You can only access the clipboard from an STA thread. Rick Brewster ran into this with some refactoring of the regular Edit->Paste command, in Paint.NET.

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

Code:

代码:

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

Code is from Rick. http://forums.getpaint.net/index.php?/topic/13712-/page__view__findpost__p__226140

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

Update: Jason Heinemade a good point of adding ()after delegateto fix the ambiguous method error.

更新Jason Heine很好地添加了()afterdelegate以修复不明确的方法错误。

回答by Jonathan Yee

For some reason BoltBait's code didn't quite work (idat was still null even after staThread.Join()). I just did Clipboard.GetText() inside of the staThread delegate instead of Clipboard.GetDataObject() and that worked fine.

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

Thanks though - your code snippet got me 99% there :)

谢谢 - 你的代码片段让我 99% 有 :)

回答by Braian Bressan

I have written this class, it works, and do the same thing and can be easily improved just adding the method who you need

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

    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

Here is the CSharp Version:

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

You can simple use it with: Vb.net:

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

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

Csharp:

夏普:

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

回答by Danilo Bargen

Honestly, I don't know what a STA thread is, but in simple projects it might solve the problem to add [STAThread]right before the Mainmethod:

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

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

It works for me, so I don't question the method ;)

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



Further information about the [STAThread]decorator is on blog post Why is STAThread required?.

关于[STAThread]装饰器的更多信息在博客文章为什么需要 STAThread?.

回答by Rubarb

This is a threading problem. We have to get the right thread and execute through delegates.

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

I am updating my properties through a timer elapsing every 500 ms. Here is the code:

我正在通过每 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
        { }
    }

Moreover I've made a proper DependencyProperty with ClipboardString:

此外,我已经使用 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); }
    }

This way it can be bound to my TextBox in XAML assuming my control or window x:Name="_this":

这样它就可以绑定到 XAML 中的我的 TextBox 假设我的控件或窗口x:Name="_this"

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

回答by Tiina

BoltBait's code did not work for IDataObject because data object loses information outside the thread. Everything works fine, if the IDataObject is used only inside the thread like this:

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