2013-12-05 3 views
8

Рассмотрим эту небольшую программу:Странное поведение с буфером обмена в C# консольное приложение

class Program 
{ 
    [STAThread] 
    static void Main(string[] args) 
    { 
     Console.WriteLine("Please copy something into the clipboard."); 
     WaitForClipboardChange(); 
     Console.WriteLine("You copied " + Clipboard.GetText()); 
     Console.ReadKey(); 
    } 

    static void WaitForClipboardChange() 
    { 
     Clipboard.SetText("xxPlaceholderxx"); 
     while (Clipboard.GetText() == "xxPlaceholderxx" && 
       Clipboard.GetText().Trim() != "") 
      Thread.Sleep(90); 
    } 
} 

Я бегу, и я скопировать строку из блокнота. Но программа просто получает пустую строку из буфера обмена и пишет «Вы скопировали».

В чем проблема? Есть ли что-то, что делает доступ к буфер обмена правдоподобным в консольном приложении?

Это профиль клиента Windows 7 SP1 x86, .NET 4.

+0

Я не думаю, что это будет иметь значение, но попробуйте '! String.IsNullOrWhitespace (Clipboard.GetText())' в цикле while. – gunr2171

+0

Спасибо, попробовал! Однако это не повлияло. – LTR

+3

@ gunr2171 Вы имеете в виду no-op вторую половину времени? Если что-то == «foo», то то, что он не равно, не имеет значения ... PS - я бы проверил, что 'Clipboard.GetText()' возвращает первый раз, когда это интересное значение (и каждый раз после него). –

ответ

9

Используйте эту функцию

static string GetMeText() 
    { 
    string res = "starting value"; 
    Thread staThread = new Thread(x => 
     { 
     try 
     { 
      res = Clipboard.GetText(); 
     } 
     catch (Exception ex) 
     { 
      res = ex.Message;    
     } 
     }); 
    staThread.SetApartmentState(ApartmentState.STA); 
    staThread.Start(); 
    staThread.Join(); 
    return res; 
    } 

В этой строке:

Console.WriteLine("You copied " + Clipboard.GetMeText()); 

Проблема заключается в том, что буфер работает только с определенными моделями многопоточности (ApartmentState.STA), так что вы должны сделать новый поток и дайте ему эту модель, этот код делает это.

+3

Разве это не его главная «[STAThread]»? –

+0

@ebyrob - похоже, но у меня была такая же проблема, и я исправил ее с помощью этой функции ... Я не уверен, что STAThread на главном работает так же, как установка его на поток - не знаю, почему, но это сработало для меня. Может быть, main не может быть STAThread в отладчике? – Hogan

+0

Очень хорошо! Это решает проблему с пустым текстом и задержку, с которой я столкнулся с другими решениями. – LTR

1

Ваш текущий код явно ждет первого перехода от "xxPlaceholderxx" к чему-либо (ваше состояние «не определенная строка и не пусто», которое оказывается ложным, как только строки меняется от "xxPlaceholderxx" ни к чему, в том числе ""):

while (Clipboard.GetText() == "xxPlaceholderxx" 
    && Clipboard.GetText().Trim() != "") 

Вы, вероятно, хотите || (или) вместо и:

// assuming System.Windows.Forms.Clipboard 
static void WaitForClipboardChange() 
{ 
    Clipboard.SetText("xxPlaceholderxx"); 
    while (Clipboard.GetText() == "xxPlaceholderxx" 
    || string.IsNullOrWhiteSpace(Clipboard.GetText())) 
     Thread.Sleep(90); 
} 
+0

Алексей, ты прав. Однако эта модификация не решает проблему. Поведение все тот же. – LTR

3

Это работает для меня:

static void Main(string[] args) 
{ 
    Console.WriteLine("Please copy something into the clipboard."); 
    string text = WaitForClipboardChange(); 
    Console.WriteLine("You copied " + text); 
} 
static string WaitForClipboardChange() 
{ 
    string placeholderText = "xxPlaceholderxx"; 
    Clipboard.SetText(placeholderText); 

    string text = null; 
    do 
    { 
     Thread.Sleep(90); 
     text = Clipboard.GetText(); 
    } 
    while (string.IsNullOrWhiteSpace(text) || text.Equals(placeholderText)); 

    return text; 
} 
+0

Да, это решает проблему! Только странно, после копирования чего-то моя программа зависает около 3 секунд. Это приемлемо (это только программное обеспечение для личного использования), но было бы интересно также исправить это. – LTR

5

Однако ClipBoard.GetText() manual состояние:

Используйте метод ContainsText, чтобы определить, содержит ли буфер обмена текстовых данных перед извлечением его с помощью этого метода.

Я воспринимаю это как инструкцию, не предложение, это так, попробуйте это:

class Program 
{ 
    [STAThread] 
    static void Main(string[] args) 
    { 
     Console.WriteLine("Please copy something into the clipboard."); 
     WaitForClipboardChange(); 
     Console.WriteLine("You copied " + Clipboard.GetText()); 
     Console.ReadKey(); 
    } 
    static void WaitForClipboardChange() 
    { 
     Clipboard.Clear(); 

     while (!Clipboard.ContainsText()) 
      Thread.Sleep(90); 
    } 
} 

Он показывает скопированный текст, хотя я должен сказать, что это позволяет моя система висит ужасно, когда я копирую некоторые текст.

+0

Спасибо, это решает проблему, как решение RobSkilos. Единственная проблема заключается в том, что программа задерживается около 3 секунд после копирования. См. Мой комментарий на ответ RobSkilos для объяснения. – LTR

+0

@LTR это делает программу, в которой я скопировал от меня зависание. Возможно, вас больше интересует ['AddClipboardFormatListener()', как описано здесь] (http://stackoverflow.com/a/11901709/266143). – CodeCaster

+0

Обновление: я использовал решение Hogan, и это исправляет и проблему из моего вопроса, и проблему с 3-секундной задержкой после копирования! – LTR

Смежные вопросы