Click here to Skip to main content
15,886,772 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Little background, my main experience has been vb.net/winforms and I've recently moved to c# and winui3 (desktop) and been banging my head to understand things. I've been going through a book called 'Learn WinUI 3.0' which has helped but isn't the greatest in explaining things.

Ok so I'm doing a project that I need to create a class and then spin it off into it's own thread. That thread then just runs in background doing things and updating properties on the main thread, which then updates the xaml gui and such. I've been having a real hard time trying to figure this out, and with winui3 desktop seemingly having some slightly different implementations of the way vb.net/uwp/wpf does it, googling has been a mess for me.

So I boiled it down to a real simple little test app here just to try and figure it out.
(I've edited the code from original to try something else, updated below)

I have a class called 'ChangeTextFromThread':
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace ThreadTest {
    public class ChangeTextFromThread {
        private bool exitthread = false;

        MainViewModel vm;
        public ChangeTextFromThread(MainViewModel mainViewModel) {
            vm = mainViewModel;
        }

        public void Start() {
            ChangeText();
        }

        private String tempstring = "";
        private int addup = 0;

        private void ChangeText() {
            do {
                addup++;          
                vm.OutputString = addup.ToString();
                Thread.Sleep(1);
                }while (!exitthread) ;          
        }
    }
}


And on my MainViewModel:
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace ThreadTest {
    public class MainViewModel : BindableBase {
        private String outputString = "Empty";
        private String inputString = "";
        private ChangeTextFromThread changeTextClass;

        public String OutputString {
            get { return outputString; }
            set { SetProperty(ref outputString, value); }
        }

        public String InputString {
            get { return inputString; }
            set { SetProperty(ref inputString, value); }
        }

        public void Test() {
            changeTextClass = new ChangeTextFromThread(this);   
            Thread changeTextThread = new Thread(changeTextClass.Start);
            changeTextThread.Start();    
        }
    }
}


And my BindableBase:
C#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;


namespace ThreadTest {
    public class BindableBase : INotifyPropertyChanged {

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged([CallerMemberName] string propertyName = null) {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        protected bool SetProperty<T>(ref T originalValue, T newValue, [CallerMemberName] string propertyName = null) {
            if (Equals(originalValue, newValue)) {
                return false;
            }

            originalValue = newValue;
            OnPropertyChanged(propertyName);

            return true;
        }

    }
}


So user presses start, which spins up a new class on a new thread and starts it. The class is supposed to just count up and update the property of 'OutputString' (which is bound to a TextBlock in XAML). I read to reference the MainViewModel to the new thread class, which I did up above and I can see the properties on the MainViewModel from the new class. But when i run it, and press the button I get this error when it tries to update the property:
System.Runtime.InteropServices.COMException: 'The application called an interface that was marshalled for a different thread. (0x8001010E (RPC_E_WRONG_THREAD))'


How do I change properties from a different thread?
Thank you if anyone can help, my brain is fried with a bad mix of old (winforms/vb) and new (winui/c#) knowledge.

What I have tried:

Various things I've googled. I know the answer is probably simple but my brain wont get over this wall.
Posted
Updated 10-Mar-22 14:08pm
v2
Comments
[no name] 10-Mar-22 21:54pm    
Use Dispatcher.Invoke(); using the Dispatcher object of the UI thread you want to update. (Controls / windows have a .Dispatcher object property)

https://docs.microsoft.com/en-us/dotnet/api/system.windows.threading.dispatcher.invoke?view=windowsdesktop-6.0
tim_c 10-Mar-22 23:06pm    
Thanks! I figured out that using "private readonly DispatcherQueue _dispatcherQueue = DispatcherQueue.GetForCurrentThread();" and "Thread changeTextThread = new Thread(changeTextClass.Start);" and starting thread that way, I can both run the thread and also update properties on the ui thread. Sadly I don't know how to close the thread yet, as Abort() is no longer supported. Is this the same or different from using the normal 'Dispatcher' that you linked?
[no name] 11-Mar-22 9:58am    
I have yet to find a practical reason to use a "while loop" to update a UI. From 40 ms to 6 seconds, all my "interval based" apps use a DispatcherTimer to update controls on other threads at a given rate. BTW, users don't perceive lag until you get to 100 ms.
tim_c 11-Mar-22 18:24pm    
Thanks I'll look into DispatcherTimer!

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900