How to Write From one Thread to Another ?

Using Microsoft Windows Presentation Foundation and Syncfusion WPF Libraries

How to Write From one Thread to Another ?

Postby PGilbert on Tue Mar 08, 2016 12:49 pm

While running a multithread WPF application that has the GUI running on one thread and the business code on another, it is not allowed that the business thread writes directly to the GUI thread.

Question: How do we do that then ?

Thanks in advance,

Pierre Gilbert
User avatar
PGilbert
 
Posts: 440
Joined: Sun Dec 13, 2009 8:46 pm
Location: Montréal, Québec, Canada

Re: How to Write From one Thread to Another ?

Postby Phil Last on Tue Mar 08, 2016 6:37 pm

When APL threads were new Jake solved this very problem very neatly for us by having the gui thread poll a set of nss each of which was allocated to another thread that wrote named variables to it asynchronously. The gui thread picked these up and displayed the data using a generic protocol.

No doubt more sophisticated solutions have become available since.
User avatar
Phil Last
 
Posts: 628
Joined: Thu Jun 18, 2009 6:29 pm
Location: Wessex

Re: How to Write From one Thread to Another ?

Postby PGilbert on Thu Mar 10, 2016 12:55 am

From a discussion with Michael Hughes it was recommended to use Data Binding or a Dispatcher to write values across threads.

Thanks Michael.
User avatar
PGilbert
 
Posts: 440
Joined: Sun Dec 13, 2009 8:46 pm
Location: Montréal, Québec, Canada

Re: How to Write From one Thread to Another ?

Postby PGilbert on Thu Mar 17, 2016 7:40 pm

Like Michael told me, it is explained on the web that you need a dispatcher to access the properties of an object that is on another thread. This is such an example in C#:

Code: Select all
textBox.Dispatcher.Dispatcher.Invoke(
      System.Windows.Threading.DispatcherPriority.Normal,
      new Action(
        delegate()
        {
          textBox.Text = "Hello World";
        }
    ));


From the WPF WS that Michael supplied me, I am trying to do a simplistic function that will do something similar in APL. So far I have this:

Code: Select all
 obj Dispatch action;ActionObj;delegate;⎕USING

 action ← ⎕FX 'RunBackground' action

 ⎕USING ← 'System,System.dll' 'System.Windows,WPF/WindowsBase.dll' 'System.Windows.Threading,WindowsBase.dll'

 action    ← Type.GetType⊂'System.Action`1'
 ActionObj ← action.MakeGenericType(⊂,Type.GetType⊂'System.Object')
 delegate  ← 2016⌶ActionObj(⎕OR'RunBackground')
 obj.Dispatcher.BeginInvoke((DispatcherPriority.Normal)delegate)


and ideally I would like to do the following:

      ⎕USING←'System.Windows,WPF/PresentationFramework.dll'
win←⎕NEW Window
win Dispatch 'win.Title←''hello world'''
EXCEPTION
Dispatch[9] obj.Dispatcher.BeginInvoke((DispatcherPriority.Normal)delegate)

⎕EXCEPTION.Message
VALUE ERROR
⎕EXCEPTION.Message


What would be the correct way to write the function 'Dispatch' ?

Thanks in advance.
User avatar
PGilbert
 
Posts: 440
Joined: Sun Dec 13, 2009 8:46 pm
Location: Montréal, Québec, Canada

Re: How to Write From one Thread to Another ?

Postby PGilbert on Thu Mar 17, 2016 9:07 pm

Found it:

      ∇Dispatch[⎕]∇
[0] obj Dispatch action;ActionObj;delegate;⎕USING
[1]
[2] action←⎕OR ⎕FX'RunBackground'action
[3]
[4] ⎕USING←'System,System.dll' 'System.Windows.Threading,WindowsBase.dll'
[5]
[6] {}obj.Dispatcher.BeginInvoke(DispatcherPriority.Normal(⎕NEW Action action))

⎕USING ← 'System.Windows,WPF/PresentationFramework.dll'
win ← ⎕NEW Window
win Dispatch& 'win.Title←''hello world'''

win.Title
hello world


The problem that I see is that all actions will be put into the same function named 'RunBackground' and if you do a couple of rapid Dispatch one after each one the 'RunBackground' executed may not be the good one.

Is there a way to fix this ?
User avatar
PGilbert
 
Posts: 440
Joined: Sun Dec 13, 2009 8:46 pm
Location: Montréal, Québec, Canada

Re: How to Write From one Thread to Another ?

Postby PGilbert on Thu Aug 18, 2016 1:39 am

Following from my previous post, looks like the Dispatcher idea can have currently some issues with the interpreter (based on my experience so far). I have resort to experiment with binding an apl variable to the DataContext of a form. The apl variable can contain a DataTable that can be used for binding (setting the DataContext directly with a DataTable across threads is not permitted in WPF). That way you can assign a DataTable to the apl variable across threads and the bind variable will change the DataContext with the value of the DataTable.

So far my experimentation has led me to the following function for this particular type of binding:
Code: Select all
 object BindVarNameToObjDataContext varName;binding;⎕USING
⍝ Binds a fully qualified existing apl variable name to the DataContext of a .Net objet.
⍝ The apl variable can contain a .Net object

⍝ varName = fully qualified existing apl variable name
⍝ object  = .Net object

 ⎕USING←'System.Windows.Data,WPF/PresentationFramework.dll' 'System.Windows,WPF/PresentationFramework.dll'

⍝ This construction will set the 'Path' of the binding that is the name of the variable without the path
⍝ The 'Path' property is a 'System.Windows.PropertyPath' that is easier to set in the constructor than as a property.
 binding←⎕NEW Binding(⊂,{(-⊥⍨⍵≠'.')↑⍵}varName)  ⍝ varName is without the path here
 binding.Source←2015⌶varName                    ⍝ varName is fully qualified with path here
 binding.Mode←BindingMode.OneWay                ⍝ Setup as One Way Binding
 binding.UpdateSourceTrigger←UpdateSourceTrigger.PropertyChanged

⍝ Setting-up the Binding to the DataContext Property:
⍝ Looks like not all the elements have a DataContextProperty even if they show it in the intellisense.
⍝ We need to use instead a FrameworkElement that has always a DataContextProperty available to do the Binding.
⍝ Using object.SetBinding is very much faster than Data.BindingOperations.SetBinding(object FrameworkElement.DataContextProperty bd)

 {}object.SetBinding(FrameworkElement.DataContextProperty binding)


All this because I have not been able to do a simple/direct binding with 2015⌶.

Question: Is there a simpler way to do this type of binding ?

Thanks in advance
User avatar
PGilbert
 
Posts: 440
Joined: Sun Dec 13, 2009 8:46 pm
Location: Montréal, Québec, Canada

Re: How to Write From one Thread to Another ?

Postby MikeHughes on Thu Aug 18, 2016 7:32 am

The way to do multiple bindings to variables is to bind a Namespace to a DataContext - not a DataTable
User avatar
MikeHughes
 
Posts: 86
Joined: Thu Nov 26, 2009 9:03 am
Location: Market Harborough, Leicestershire, UK

Re: How to Write From one Thread to Another ?

Postby PGilbert on Thu Aug 18, 2016 11:49 am

Hello Michael, I was meaning if there is a simpler way to write the function 'BindVarNameToObjDataContext'.
User avatar
PGilbert
 
Posts: 440
Joined: Sun Dec 13, 2009 8:46 pm
Location: Montréal, Québec, Canada

Re: How to Write From one Thread to Another ?

Postby MikeHughes on Fri Aug 19, 2016 7:08 am

Yes, the namespace binding does use the ibeam

:Trap 0
{}Reset ns
:If 0=×/⍴type ⋄ obj.DataContext←(2015⌶)ns ⍝ Assign DataContext
:Else ⋄ obj.DataContext←type(2015⌶)ns ⍝ Assign DataContext with export definition
:EndIf
:Else ⋄ 'Trouble setting DataContext'⎕SIGNAL 90 ⍝ or throw exception
:EndTrap


{r}←Reset name
⍝ Resets the binding on the variable or namespace named in the argument

r←(2014⌶)name
⍝ c mjh 26Sep2014
User avatar
MikeHughes
 
Posts: 86
Joined: Thu Nov 26, 2009 9:03 am
Location: Market Harborough, Leicestershire, UK

Re: How to Write From one Thread to Another ?

Postby PGilbert on Fri Aug 19, 2016 12:06 pm

Thanks Michael, in our case we want to show the value of a log file in our application. An item of the log file is some HTML with a message (color of the text will vary depending if it is an alarm or status) or a capture screen of the application (save as base64 in an inline png). Since the log file can be too big for the size of the workspace we save it in a CSV file outside the workspace (easy to add another item of the log that way too). We have found a third party dll that will read the CSV file and return a .net DataTable without having a single byte transiting in the workspace. Once we have the DataTable it is bind to a CollectionViewSource with a ListBox that contains some Syncfusion RichTextBoxAdv that will render the individual HTML items. The WPF ListBox will do some 'virtualizing' so we can see right away the items of the log that are in the view and the other items will be rendered only when we scroll (otherwise it is too long to wait for all the items to be rendered before viewing only the couple first ones).

We do on another thread the conversion of the CSV file to a DataTable and the binding hence my question on this forum.

It is a little bit hard to do the first time but the result is quite spectacular (the items of each day are group together in a custom .net Expander). There is a possibility that Dyalog will allow, in the future, the binding of a function. I think it would than be possible to bind a component file (via that function) and it will be much easier to do the same thing (looking forward for that Dyalog).

Thanks Michael for your help.
User avatar
PGilbert
 
Posts: 440
Joined: Sun Dec 13, 2009 8:46 pm
Location: Montréal, Québec, Canada

Next

Return to WPF & Syncfusion

Who is online

Users browsing this forum: Google [Bot] and 1 guest