Why TextBlock.Text doesn't get updated the first time (of two) I set its content? and how to resolve/work-around it?

0

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:

  1. Using PreviewMouseDoubleClick to do CopiedToClipboardTextBlock.Text = "Copying...". Didn't help...
  2. Using new thread in which 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...)

Update:

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.

c#
wpf
multithreading
dispatcher
asked on Stack Overflow Sep 15, 2014 by Tar • edited Jun 20, 2020 by Community

1 Answer

2

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));
answered on Stack Overflow Sep 15, 2014 by mt_serg

User contributions licensed under CC BY-SA 3.0