✅ ERROR: The calling thread cannot access this object because a different thread owns it.

Hey, I'm getting this error The calling thread cannot access this object because a different thread owns it. from the following method when trying to add a Run element to a RichTextBox I've tried Googling a ton and even tried ChatGPT to see if it could fix it for me, all answers point to use chatRichTextBox.Dispatcher.Invoke but it still fails, any ideas?
private void AddChatMessage(string username, string message, System.Drawing.Color usernameColor)
{
System.Windows.Media.Color mediaColor = System.Windows.Media.Color.FromArgb(usernameColor.A, usernameColor.R, usernameColor.G, usernameColor.B);

var usernameRun = new Run(username)
{
Foreground = new SolidColorBrush(mediaColor),
FontWeight = FontWeights.Bold
};
var messageRun = new Run(": " + message)
{
Foreground = Brushes.White
};

var paragraph = new Paragraph();
paragraph.Inlines.Add(usernameRun);
paragraph.Inlines.Add(messageRun);

// Ensure the UI update is done on the UI thread
chatRichTextBox.Dispatcher.Invoke(() =>
{
chatRichTextBox.Document.Blocks.Add(paragraph);
chatRichTextBox.ScrollToEnd();
});
}
private void AddChatMessage(string username, string message, System.Drawing.Color usernameColor)
{
System.Windows.Media.Color mediaColor = System.Windows.Media.Color.FromArgb(usernameColor.A, usernameColor.R, usernameColor.G, usernameColor.B);

var usernameRun = new Run(username)
{
Foreground = new SolidColorBrush(mediaColor),
FontWeight = FontWeights.Bold
};
var messageRun = new Run(": " + message)
{
Foreground = Brushes.White
};

var paragraph = new Paragraph();
paragraph.Inlines.Add(usernameRun);
paragraph.Inlines.Add(messageRun);

// Ensure the UI update is done on the UI thread
chatRichTextBox.Dispatcher.Invoke(() =>
{
chatRichTextBox.Document.Blocks.Add(paragraph);
chatRichTextBox.ScrollToEnd();
});
}
10 Replies
leowest
leowest2mo ago
Instead of using a ricthtextbox, you could use a itemscontrol, u create a datatemplate add some scrolling then you can use an ObservableCollection<Message> and instead of all that u would just add items to the Observable collection and it would update your ui This is just an idea:
<Grid Margin="10">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding Messages}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock>
<Run Foreground="{Binding UsernameColor}" FontWeight="Bold" Text="{Binding Username}" />
<Run Foreground="{Binding MessageColor}" Text=": " />
<Run Foreground="{Binding MessageColor}" Text="{Binding Message}" />
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
<Grid Margin="10">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding Messages}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock>
<Run Foreground="{Binding UsernameColor}" FontWeight="Bold" Text="{Binding Username}" />
<Run Foreground="{Binding MessageColor}" Text=": " />
<Run Foreground="{Binding MessageColor}" Text="{Binding Message}" />
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
And by adding items to:
public ObservableCollection<ChatMessage> Messages { get; set; } = new ObservableCollection<ChatMessage>();
public ObservableCollection<ChatMessage> Messages { get; set; } = new ObservableCollection<ChatMessage>();
It would populate the ItemsControl https://wpf-tutorial.com/list-controls/itemscontrol/
Delicious Cake
Delicious Cake2mo ago
That's an excellent example! Unfortunately it still gives me this error when I try to add the messages :( Line: ChatHistoryCollection.Add(new ChatMessage { UsernameColour= new SolidColorBrush(mediaColor), Username = username, Message = message }); Error: System.NotSupportedException: 'This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.'
leowest
leowest2mo ago
yes now u have to use the dispatcher because you're calling it from a different thread
Delicious Cake
Delicious Cake2mo ago
Am I doing something wrong in the MainWindow constructor?
public MainWindow()
{
InitializeComponent();
_synthesizer = new SpeechSynthesizer();
InitializeTwitchClient();
DataContext = this;
}
public MainWindow()
{
InitializeComponent();
_synthesizer = new SpeechSynthesizer();
InitializeTwitchClient();
DataContext = this;
}
Ah okay I'll give that a go first Like this?
Application.Current.Dispatcher.Invoke(() =>
{
ChatHistoryCollection.Add(new ChatMessage { UsernameColour = new SolidColorBrush(mediaColor), Username = username, Message = message });
});
Application.Current.Dispatcher.Invoke(() =>
{
ChatHistoryCollection.Add(new ChatMessage { UsernameColour = new SolidColorBrush(mediaColor), Username = username, Message = message });
});
leowest
leowest2mo ago
should work ChatHistoryCollection is a public property right?
Delicious Cake
Delicious Cake2mo ago
That worked! Not getting the colour I expected from the username though, that might be cause either converting it wrong or grabbing the wrong value from TwitchLib's OnMessageReceivedArgs
leowest
leowest2mo ago
yeah I wouldn't know about that I never used that lib and if u want the messages order to be inverted just change it to Insert(0, new ChatMessage.... instead of Add then u avoid having to scroll unless u want to see old messages
Delicious Cake
Delicious Cake2mo ago
Amazing, thank you for the help :)
leowest
leowest2mo ago
no worries, $close
MODiX
MODiX2mo ago
If you have no further questions, please use /close to mark the forum thread as answered