Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accessing UI (Main) Thread safely in WPF

I have an application which updates my datagrid each time a log file that I'm watching gets updated (Appended with new text) in the following manner:

private void DGAddRow(string name, FunctionType ft)     {                 ASCIIEncoding ascii = new ASCIIEncoding();      CommDGDataSource ds = new CommDGDataSource();      int position = 0;     string[] data_split = ft.Data.Split(' ');     foreach (AttributeType at in ft.Types)     {         if (at.IsAddress)         {              ds.Source = HexString2Ascii(data_split[position]);             ds.Destination = HexString2Ascii(data_split[position+1]);             break;         }         else         {             position += at.Size;         }     }     ds.Protocol = name;     ds.Number = rowCount;     ds.Data = ft.Data;     ds.Time = ft.Time;      dataGridRows.Add(ds);       rowCount++;     }     ...     private void FileSystemWatcher()     {         FileSystemWatcher watcher = new FileSystemWatcher(Environment.CurrentDirectory);         watcher.Filter = syslogPath;         watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite             | NotifyFilters.FileName | NotifyFilters.DirectoryName;         watcher.Changed += new FileSystemEventHandler(watcher_Changed);         watcher.EnableRaisingEvents = true;     }      private void watcher_Changed(object sender, FileSystemEventArgs e)     {         if (File.Exists(syslogPath))         {             string line = GetLine(syslogPath,currentLine);             foreach (CommRuleParser crp in crpList)             {                 FunctionType ft = new FunctionType();                 if (crp.ParseLine(line, out ft))                 {                     DGAddRow(crp.Protocol, ft);                 }             }             currentLine++;         }         else             MessageBox.Show(UIConstant.COMM_SYSLOG_NON_EXIST_WARNING);     } 

When the event is raised for the FileWatcher, because it creates a separate thread, when I try to run dataGridRows.Add(ds); to add the new row, the program just crashes without any warning given during debug mode.

In Winforms, this was easily solved by utilizing the Invoke function but I am not sure how to go about this in WPF.

like image 559
l46kok Avatar asked Jul 24 '12 06:07

l46kok


People also ask

What is UI thread in WPF?

The UI thread queues work items inside an object called a Dispatcher. The Dispatcher selects work items on a priority basis and runs each one to completion. Every UI thread must have at least one Dispatcher, and each Dispatcher can execute work items in exactly one thread.

Is WPF multithreaded?

WPF supports a single-threaded apartment model that has the following rules: One thread runs in the entire application and owns all the WPF objects. WPF elements have thread affinity, in other words other threads can't interact with each other.

What is thread affinity in WPF?

So thread affinity means that the thread, in this case the UI thread that instantiates an object is the only thread that can access its members. So for example, dependency object in WPF has thread affinity.

How many threads are there in WPF?

WPF applications start their lives with two threads: one for rendering and another for the UI. The rendering thread runs hidden in the background while the UI thread receives input, handles events, paints the screen, and runs application code. The UI thread queues work items inside an object called a Dispatcher.


1 Answers

You can use

Dispatcher.Invoke(Delegate, object[])

on the Application's (or any UIElement's) dispatcher.

You can use it for example like this:

Application.Current.Dispatcher.Invoke(new Action(() => { /* Your code here */ })); 

or

someControl.Dispatcher.Invoke(new Action(() => { /* Your code here */ })); 
like image 156
Botz3000 Avatar answered Oct 05 '22 08:10

Botz3000