How do I tell if my current thread is the UI thread?
Asked Answered
S

2

17

I'm working on a user control for UWP and it updates some of its visuals upon certain calls. However, since the core .NET library has been shifted around and the threading classes have been severely cut back, I don't know how to identify from the method in the user control if the calling thread is the UI thread or not so it knows whether or not to use the dispatcher to change a dependency property.

Anyone know how to do this?

EDIT: The dispatcher functionally can be "invoked" async fine on the UI thread - however, I really don't know if this is a good idea - to try to invoke on the main thread from the main thread via the dispatcher. If anyone has a reason this is fine or bad, that would also contribute to answering the question. If there's no reason to not use the dispatcher on the main thread, then I guess there's no problem.

Sophiesophism answered 20/8, 2015 at 2:13 Comment(8)
Can't you just always call RunAsync?Kowalewski
@X-TECH unlikely correct duplicate - notice "uwp" tag which significantly changes available APIs.Kowalewski
@AlexeiLevenkov Yes, System.Thread is not available.Sophiesophism
@x-Tech That answer utilizes System.Thread, an API not available in UWPSophiesophism
@AlexeiLevenkov Is this ok? I felt like it was a strange thing to try to be creating async tasks for the thread it's on...Sophiesophism
I'd use it without thinking much, but Store apps is not area I have any reasonable experience - so can't say if there is better way. Generally so overhead for synchronous async tasks (when task is completed on the same thread synchronously) is relatively low. The only thing I'd do is bundle all updates into single call if possible.Kowalewski
IMHO always calling RunAsync() is fine. Frankly, IMHO it would be better to design the code so that property updates are done only from the appropriate thread. It is generally easy to stay on the UI thread, except for background operations, pushing updates back to the UI thread. But if you find yourself in a situation where that can't work, just calling the RunAsync() or similar will work. See my related rant here: blogs.msmvps.com/duniho/2008/09/12/…Redden
@PeterDuniho In this case I'm trying to rig up my singleton "console/logging" class which needs to be readily available from any thread and fires an event when a line is added, which, in turn, updates the viewmodel which must be done from the main thread so I can't be sure I'm always on the UI thread. I'm just working on setting up a testing environment for UWP for now and figured I'd make a control for my console singleton to display its feed so I don't have to rerig it if I use it in an application.Sophiesophism
S
22

I have found the solution...

CoreDispatcher.HasThreadAccess returns a bool indicating if you are on the UI thread or not.

Sophiesophism answered 20/8, 2015 at 3:16 Comment(2)
It should be noted that in a UWP app, the UI thread is not Main thread. It's easy to check with debugger. For example, a breakpoint in the Loaded event handler of a page shows that Dispatcher.HasThreadAccess == true, and current thread is "Worker Thread" with "No name" and "Managed ID" == 3Strident
The CoreDispatcher can be accessed via CoreWindow.GetForCurrentThread().Dispatcher. Took me a little while to find :PCollision
A
2

My son just encountered this as an Issue so I thought I would add an updated answer.

The Main UI thread can be accessed using the Core Dispatcher CoreWindow.GetForCurrentThread().Dispatcher or Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher

Below is a class that implements the Core Dispatcher and tests whether the calling thread is the Main UI Thread. If so it invokes the action, otherwise calls Dispatcher.RunAsync to execute it on the Main UI thread.

class Threading {

     private static CoreDispatcher Dispatcher => 
     Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher;

     public static async void ThreadSafe(DispatchedHandler action)
        {
            // Calls Dispatcher.RunAsync to run a method on the Main UI Thread
            IAsyncAction UiThread(DispatchedHandler proc) => Dispatcher.RunAsync(CoreDispatcherPriority.Normal, proc);

            // Checks to see if this was called from the Main UI thread 
            // If we are in the Main UI thread then Invoke the action 
            // Otherwise: Send it to run in the Main Ui Thread.

            if (Dispatcher.HasThreadAccess) { action.Invoke(); } else { await UiThread(action); };
        }
    }

The above class could be used like so:

// Some event handler callback
private void SomeCallback(object sender)(){
    void line() => Frame.Navigate(typeof(PageName));
    Threading.ThreadSafe(line);
}

// Pass a handle to the control and a string to update it's text property
internal static void ChangeControlText(dynamic ctrl , string v)
    {
                void line() {ctrl.Text= v;}
                ThreadSafe(line);
    }
Arin answered 12/8, 2020 at 12:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.