{"id":9246,"date":"2015-05-27T06:00:00","date_gmt":"2015-05-27T13:00:00","guid":{"rendered":"https:\/\/www.sapien.com\/blog\/?p=9246"},"modified":"2015-05-27T06:57:08","modified_gmt":"2015-05-27T13:57:08","slug":"copy-to-clipboard-in-a-gui-application","status":"publish","type":"post","link":"https:\/\/dev.sapien.com\/blog\/2015\/05\/27\/copy-to-clipboard-in-a-gui-application\/","title":{"rendered":"Copy to Clipboard in a GUI Application"},"content":{"rendered":"<p><a class=\"twitter-follow-button\" href=\"https:\/\/twitter.com\/juneb_get_help\" data-lang=\"en\">Follow @juneb_get_help<\/a><\/p>\n<p>During <a href=\"https:\/\/www.sapien.com\/blog\/2015\/04\/03\/advanced-help-for-advanced-functions\/\" target=\"_blank\">#PSBlogWeek<\/a>, I shared with my co-authors a little GUI-based blogging tool that gets links to the online version of PowerShell help topics, including About topics. I didn&#8217;t think much of it, because it was my first GUI app, but I soon received a nice compliment from PowerShell MVP Jeffery Hicks with a suggestion to add a &#8220;Copy to clipboard&#8221; button to the app. It was a great suggestion, so I set aside some time to implement it.val<\/p>\n<p>It didn&#8217;t take much time at all!<\/p>\n<h1>Using Clip.exe<\/h1>\n<p>I started by creating a little GUI app to isolate and test the copy-to-clipboard feature. When the user types text in the &#8220;Type here&#8221; text box and clicks <strong>Copy to clipboard<\/strong>,&#8221; the app copies the text in the textbox and saves it in the clipboard to be pasted elsewhere.<\/p>\n<p><a href=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2015\/05\/image5.png\"><img loading=\"lazy\" decoding=\"async\" style=\"display: inline; border: 0px;\" title=\"image\" src=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2015\/05\/image_thumb3.png\" alt=\"image\" width=\"286\" height=\"192\" border=\"0\" \/><\/a><\/p>\n<p>Implementation is pretty simple. When the text in the input textbox changes, I verify that it&#8217;s not an empty string and then enable the <strong>Copy to clipboard<\/strong> button.<\/p>\n<pre lang=\"PowerShell\">$textboxInput_TextChanged={\r\n    if ($textboxInput.Text.Trim() -ne \"\")\r\n    {\r\n        $buttonCopyToClipboard.Enabled = $true\r\n    }\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p>For my first try at implementing the copy-to-clipboard feature, in the Click event of the Copy to Clipboard button, I got the Text property of the input textbox ($textboxInput.Text), trimmed it, and piped it to Clip.exe.<\/p>\n<pre lang=\"PowerShell\">$buttonCopyToClipboard_Click={\r\n    $textboxInput.Text.Trim() | Clip\r\n}<\/pre>\n<p>When I tested the app, it copied the text in the input text box to the clipboard as expected, but, in the process, it opened and closed a command prompt window. It was quick, but you could see the window flash and I wasn&#8217;t happy with the experience.<\/p>\n<p>&nbsp;<\/p>\n<h1>Using the Clipboard Class<\/h1>\n<p>Next, I tried the <strong>Copy to clipboard<\/strong> snippet in PowerShell Studio 2015. It invokes the <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/ydby206k(v=vs.110).aspx\" target=\"_blank\">SetText<\/a> static method of the <strong><a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/System.Windows.Forms.Clipboard(v=vs.110).aspx\" target=\"_blank\">Clipboard class<\/a><\/strong> (System.Windows.Forms.Clipboard).<\/p>\n<pre lang=\"PowerShell\">$buttonCopyToClipboard_Click={\r\n    [System.Windows.Forms.Clipboard]::SetText($textboxInput.Text.Trim())\r\n}<\/pre>\n<p>That worked perfectly! I could have stopped there, but I wanted to explore some other ways of copying to the clipboard.<\/p>\n<p>&nbsp;<\/p>\n<h1>Using the Copy Method<\/h1>\n<p>The <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/system.windows.forms.textbox(v=vs.110).aspx\" target=\"_blank\">Textbox class<\/a> (System.Windows.Forms.Textbox) has a <strong><a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/system.windows.forms.textboxbase.copy(v=vs.110).aspx\" target=\"_blank\">Copy<\/a><\/strong> method that copies the text in a Textbox to the clipboard. It&#8217;s very simple to read and to use, because it doesn&#8217;t have any parameters. Even better, Textbox controls actually &#8220;inherit&#8221; this method from their parent class, <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/system.windows.forms.textboxbase(v=vs.110).aspx\" target=\"_blank\">TextBoxBase<\/a>, which means that the Copy method also works in other textbox controls with the same parent class, including <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/system.windows.forms.richtextbox(v=vs.110).aspx\" target=\"_blank\">RichTextbox<\/a> and <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/system.windows.forms.maskedtextbox(v=vs.110).aspx\" target=\"_blank\">MaskedTextbox<\/a>.<\/p>\n<p>I was sold on the Copy() method &#8230; except for one problem.<\/p>\n<pre lang=\"PowerShell\">$buttonCopyToClipboard_Click={\r\n    $textBoxInput.Copy()\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p>It didn&#8217;t work. It didn&#8217;t generate any errors, but it didn&#8217;t copy the text in the input textbox to the clipboard.<\/p>\n<p>To figure out why, I read the Copy method description really carefully and examined the examples in C#, C++, and VB, because they don&#8217;t have PowerShell examples on the .NET reference pages.<\/p>\n<p>&#8220;Copies the current selection in the text box to the Clipboard.&#8221;<\/p>\n<p>Aha! Selection. It copies the &#8220;selected&#8221; text in the textbox to the clipboard.<\/p>\n<p>To select text from the Textbox, you use the <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/system.windows.forms.textboxbase.select(v=vs.110).aspx\" target=\"_blank\">Select<\/a> or <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/system.windows.forms.textboxbase.selectall(v=vs.110).aspx\" target=\"_blank\">SelectAll<\/a> methods of the Textbox. To keep it simple, I used SelectAll.<\/p>\n<pre lang=\"PowerShell\">$buttonCopyToClipboard_Click={\r\n    $textboxInput.SelectAll()\r\n    $textBoxInput.Copy()\r\n}<\/pre>\n<p>Excellent. That&#8217;s another technique that I can use. Let&#8217;s see what lurks in the PowerShell 5.0 preview.<\/p>\n<h1>Using Set-Clipboard<\/h1>\n<p>The Windows PowerShell 5.0 preview includes new <a href=\"http:\/\/go.microsoft.com\/fwlink\/?LinkId=526219\" target=\"_blank\">Get-Clipboard<\/a> and <a href=\"http:\/\/go.microsoft.com\/fwlink\/?LinkId=526220\" target=\"_blank\">Set-Clipboard<\/a> cmdlets with cool parameters like Append, Format, and Raw. The Value parameter\u00a0of Set-Clipboard takes value from the pipeline, so i just piped the trimmed text in the textbox to Set-Clipboard.<\/p>\n<pre lang=\"PowerShell\">$buttonCopyToClipboard_Click={\r\n    $textBoxInput.Text.Trim() | Set-Clipboard\r\n}<\/pre>\n<p>This worked perfectly. The only problem is that it requires PowerShell 5.0, which is brand new and still in preview. I want my app to run on most platforms.<\/p>\n<p>&nbsp;<\/p>\n<h1>Finishing Touches: StatusBar<\/h1>\n<p>After experimenting with the variety of Copy techniques in the Copy to Clipboard form, I added the SetText() method to my blogging app. It worked just fine, but clicking the <strong>Copy to clipboard<\/strong> button wasn&#8217;t very satisfying to me without some confirmation that the copy operation actually worked.<\/p>\n<p>After the copy operation, I wanted to confirm that the text on the clipboard matched the text in the input textbox, and then let the user know about it. But, none of the copy or set\u00a0methods returns an object, or even an error.<\/p>\n<p>I used the <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/a3cyzt72(v=vs.110).aspx\" target=\"_blank\">ContainsText<\/a> (is there anything on the clipboard?) and <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/kz40084e(v=vs.110).aspx\" target=\"_blank\">GetText<\/a> (get the text on the clipboard) static methods of the Clipboard class. Because an \u2013AND statement in Windows PowerShell doesn&#8217;t test the second condition if the first fails, I used the \u2013AND to invoke both the ContainsText()\u00a0 and GetText\u00a0 methods.<\/p>\n<pre lang=\"PowerShell\">if ([System.Windows.Forms.Clipboard]::ContainsText() \u2013AND \r\n    [System.Windows.Forms.Clipboard]::GetText() ... )<\/pre>\n<p>&nbsp;<\/p>\n<p>Then, I compared the Text in the textbox \u2013 the text that I wanted to copy &#8212; to the text that GetText() found on the clipboard.<\/p>\n<pre lang=\"PowerShell\">if ([System.Windows.Forms.Clipboard]::ContainsText() \u2013AND\r\n[System.Windows.Forms.Clipboard]::GetText() \u2013eq $textboxInput.Text.Trim() )\r\n...<\/pre>\n<p>&nbsp;<\/p>\n<p>Finally, I added a <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/system.windows.forms.statusbar(v=vs.110).aspx\" target=\"_blank\">StatusBar<\/a> to my form. If the copy succeeded, I set the Text in the StatusBar to &#8220;Copied to clipboard&#8221; and made the status bar visible. I didn&#8217;t want the StatusBar hanging around there all the time, so I used the <a href=\"http:\/\/go.microsoft.com\/fwlink\/p\/?linkid=294018\" target=\"_blank\">Start-Sleep<\/a> cmdlet to count 2 seconds, and then I changed the Visible property of the StatusBar to $false.<\/p>\n<p>Here&#8217;s the Click event for the Copy to Clipboard button:<\/p>\n<pre lang=\"PowerShell\">$buttonCopyToClipboard_Click={\r\n    $copyText = $textBoxInput.Text.Trim()\r\n\r\n    [System.Windows.Forms.Clipboard]::SetText($copyText)\r\n\r\n    if ([System.Windows.Forms.Clipboard]::ContainsText() -AND\r\n        [System.Windows.Forms.Clipboard]::GetText() -eq $copyText)\r\n    {\r\n        $statusbar1.Text = \"Copied to clipboard.\"\r\n        $statusbar1.Visible = $true\r\n        Start-Sleep -Seconds 2\r\n        $statusbar1.Visible = $false\r\n    }\r\n}<\/pre>\n<p>And, here&#8217;s a demo of it working in my GUI test app.<\/p>\n<div style=\"width: 484px;\" class=\"wp-video\"><video class=\"wp-video-shortcode\" id=\"video-9246-1\" width=\"484\" height=\"436\" preload=\"metadata\" controls=\"controls\"><source type=\"video\/mp4\" src=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2015\/05\/CopyToClipboard.mp4?_=1\" \/><a href=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2015\/05\/CopyToClipboard.mp4\">https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2015\/05\/CopyToClipboard.mp4<\/a><\/video><\/div>\n<p>&nbsp;<\/p>\n<p>Finally, I added the copy code to my blogging tool, with just a few tweaks to get the control names right.\u00a0The\u00a0Copy to Clipboard feature is\u00a0easy and quick\u00a0to implement and it\u00a0results in a more fluid experience. I guess Mr. Hicks knows his stuff!<\/p>\n<p><i>June Blender is a technology evangelist at SAPIEN Technologies, Inc. You can reach her at <a href=\"mailto:juneb@sapien.com\">juneb@sapien.com<\/a> and follow her on Twitter at <a href=\"https:\/\/twitter.com\/juneb_get_help\">@juneb_get_help<\/a>.<\/i><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Follow @juneb_get_help During #PSBlogWeek, I shared with my co-authors a little GUI-based blogging tool that gets links to the online version of PowerShell help topics, including About topics. I didn&#8217;t think much of it, because it was my first GUI app, but I soon received a nice compliment from PowerShell MVP Jeffery Hicks with a [&hellip;]<\/p>\n","protected":false},"author":31,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[932,946,25],"tags":[934,28,1016],"class_list":["post-9246","post","type-post","status-publish","format-standard","hentry","category-beginners","category-guiprogramming","category-windows-powershell","tag-juneb","tag-powershell","tag-powershell-studio"],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/posts\/9246","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/users\/31"}],"replies":[{"embeddable":true,"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/comments?post=9246"}],"version-history":[{"count":26,"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/posts\/9246\/revisions"}],"predecessor-version":[{"id":9301,"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/posts\/9246\/revisions\/9301"}],"wp:attachment":[{"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/media?parent=9246"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/categories?post=9246"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/tags?post=9246"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}