Clipboard.SetText(...)
very often creates considerable delay in my GUI. Set aside for now "correct-programming/design", I want to tell the user to wait a moment (line #01
), and then let him/her know if succeeded or failed (lines #06
and #10
). The thing is that I never see the "Copying..."
text (line #01
):
01| CopiedToClipboardTextBlock.Text = "Copying...";
02| try
03| {
04| // May cause considerable delay and GUI-freeze for a while...
05| Clipboard.SetText(textBlockContent);
06| CopiedToClipboardTextBlock.Text = "Copied to clipboard:\n" + textBlockContent;
07| }
08| catch (Exception e)
09| {
10| CopiedToClipboardTextBlock.Text = "Failed to copy to clipboard!";
11| }
So I thought - OK, maybe the GUI gets updated only when the event handler returns (which doesn't make sense to me...), so I tried many things, among others:
PreviewMouseDoubleClick
to do CopiedToClipboardTextBlock.Text = "Copying..."
. Didn't help...Dispatcher.Invoke
in new thread (don't event start... I know it's quite stupid... I was desperate)(BTW, the delay in Clipboard.SetText(...)
happens when it's about to fail. The failure is COMException: OpenClipboard Failed (Exception from HRESULT: 0x800401D0 (CLIPBRD_E_CANT_OPEN))
, which is almost inevitable in many cases, but that's not the main issue here...)
This is my workaround:
CopiedToClipboardTextBlock.Text = "Copying...";
Exception resultException = null;
await Task.Run(() =>
{
var t = new Thread(obj =>
{
try { Clipboard.SetText(textBlockContent); }
catch (COMException e) { resultException = e; }
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
t.Join();
});
if (resultException == null)
CopiedToClipboardTextBlock.Text = "Copied to clipboard:\n" + textBlockContent;
else
CopiedToClipboardTextBlock.Text = "Failed to copy to clipboard!";
The inner Thread
is due to the requirement to have STA
by Clipboard.SetText(...)
function.
I don't know, seems very verbose to me. I suspect there's a simpler solution.
Yes, GUI updates only when the event handler returns (because event handler are called inside UI thread which is responsible for GUI updating). To update the text before long operation you should invoke the operation in background thread. So event handler will be freed and GUI will be refreshed.
Try to set clipboard text like this:
await Task.Run(() => Clipboard.SetText(textBlockContent));
User contributions licensed under CC BY-SA 3.0