Update UI from different thread.
Hi,
I'm trying to update the Ui from a different thread.
Thought the simplest way todo this would be through the OnPropertyChanged function like so:
But it seems that CheckAccess() always returns true no matter from which thread its called.
So i implemented my own "Thread-id-watcher" like so:
Now the call from the Non-UI thread correctly goes to the "else" but it is still a hit and miss in that i get a "System.AccessViolationException".
When its a hit and the ui actually gets updated the console puts out:
Error : The calling thread (18080) cannot access this Slidecrew_Noesis.MainWindow because a different thread (36032) owns it
Error : The calling thread (18080) cannot access this View because a different thread (36032) owns it
Error : The calling thread (18080) cannot access this Border because a different thread (36032) owns it
Error : The calling thread (18080) cannot access this View because a different thread (36032) owns it
Error : The calling thread (18080) cannot access this ContentPresenter because a different thread (36032) owns it
Error : The calling thread (18080) cannot access this View because a different thread (36032) owns it
Error : The calling thread (18080) cannot access this Grid because a different thread (36032) owns it
Error : The calling thread (18080) cannot access this View because a different thread (36032) owns it
Error : The calling thread (18080) cannot access this StackPanel because a different thread (36032) owns it
Error : The calling thread (18080) cannot access this Grid because a different thread (36032) owns it
Error : The calling thread (18080) cannot access this View because a different thread (36032) owns it
My 2 button commands:
EDIT:
I believe i fixed it.
The trick was to cache the SynchronizationContext during initializiation. And use that to send functions to the correct thread.
I'm trying to update the Ui from a different thread.
Thought the simplest way todo this would be through the OnPropertyChanged function like so:
Code: Select all
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
if (Dispatcher.CurrentDispatcher.CheckAccess())
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
else
{
//Dispatcher.CurrentDispatcher.Invoke(() => { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); });
Dispatcher.CurrentDispatcher.Invoke(() => { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); });
}
}
So i implemented my own "Thread-id-watcher" like so:
Code: Select all
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
if (_threadId == Thread.CurrentThread.ManagedThreadId)
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
else
{
//Dispatcher.CurrentDispatcher.BeginInvoke(() => { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); }); //no effect at all.
Dispatcher.CurrentDispatcher.Invoke(() => { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); });
}
}
public int _threadId;
public ViewModelBase()
{
_threadId = Thread.CurrentThread.ManagedThreadId;
}
When its a hit and the ui actually gets updated the console puts out:
Error : The calling thread (18080) cannot access this Slidecrew_Noesis.MainWindow because a different thread (36032) owns it
Error : The calling thread (18080) cannot access this View because a different thread (36032) owns it
Error : The calling thread (18080) cannot access this Border because a different thread (36032) owns it
Error : The calling thread (18080) cannot access this View because a different thread (36032) owns it
Error : The calling thread (18080) cannot access this ContentPresenter because a different thread (36032) owns it
Error : The calling thread (18080) cannot access this View because a different thread (36032) owns it
Error : The calling thread (18080) cannot access this Grid because a different thread (36032) owns it
Error : The calling thread (18080) cannot access this View because a different thread (36032) owns it
Error : The calling thread (18080) cannot access this StackPanel because a different thread (36032) owns it
Error : The calling thread (18080) cannot access this Grid because a different thread (36032) owns it
Error : The calling thread (18080) cannot access this View because a different thread (36032) owns it
My 2 button commands:
Code: Select all
public void OnCommand(object arg)
{
ButtonText = "Called from UI Thread";
}
public void OnCommandNewThread(object arg)
{
new Thread(new ThreadStart(() => { ButtonText = "Called from NON-UI Thread"; })).Start();
}
EDIT:
I believe i fixed it.
The trick was to cache the SynchronizationContext during initializiation. And use that to send functions to the correct thread.
Code: Select all
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
if (_dispatcher == Dispatcher.CurrentDispatcher.SynchronizationContext)
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(name));
else
{
_dispatcher.Post(new SendOrPostCallback((e) =>
{
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(name));
}), name);
}
}
private SynchronizationContext _dispatcher;
public ViewModelBase()
{
_dispatcher = Dispatcher.CurrentDispatcher.SynchronizationContext;
}
public event PropertyChangedEventHandler PropertyChanged;
-
sfernandez
Site Admin
- Posts: 3005
- Joined:
Re: Update UI from different thread.
I was going to say that you shouldn't use Dispatcher.CurrentDispatcher.CheckAccess() because that returns the dispatcher for the current thread, so it will always have access.
And that you would probably need to store the Dispatcher used for the UI, so you can check against it, something like:
And that you would probably need to store the Dispatcher used for the UI, so you can check against it, something like:
Code: Select all
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
if (TheUIDispatcher.CheckAccess())
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
else
{
TheUIDispatcher.Invoke(() => { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); });
}
}
Re: Update UI from different thread.
Besides the issue with the dispatcher, async DataContexts are tricky. Make sure you are implementing them right. There is a good article on the MSDN.
I am going to mark this as solved.
I am going to mark this as solved.
Who is online
Users browsing this forum: No registered users and 5 guests