In my application I have a communication driver that communicates with a PLC, this works fine. I would like to manage all value update requests, for this i created the ValueListener object who registers itself in a ValueListenManager, this also works fine. In my synchronous tests UI performance was sluggish as expected. Perfect now let's make it async.
I tried different approaches like backgroundworker, timer and Task.Run this is the best i could do so far, it works and if i printscreen the tasks ManagedThreadId threads ID's are different (what tells me it should be async)
But UI response performance does not really seems to improve, this tells me it is not really async. Can anyone help me with this?
The only weird thing i found so far is that ValueListener's can be added to the Managers ListenList while the CheckPlcValuesTask already updates, this also suggests me that it is not really async, what am i doing wrong? (i'm new to async programming so any help or tips are appreciated)
EDIT: code does now compile
public class CommManager
{
public static class ValueListenManager
{
static private List<ValueListener> ListenList = new List<ValueListener>();
public async static void Start()
{
var UpdateChangedValues = new Progress<List<ValueListener>>(UiUpdateList =>
{
foreach (ValueListener item in UiUpdateList)
item.TriggerChange();
});
await Task.Run(() => CheckPlcValuesTask(UpdateChangedValues));
}
private static Task CheckPlcValuesTask(IProgress<List<ValueListener>> progressList)
{
List<ValueListener> returnList = new List<ValueListener>();
while (true)
{
if (returnList.Count != 0)
returnList.Clear();
Parallel.ForEach(ListenList, (CurrentItem) => // ListenList is the static List declared in the top
{
if (CurrentItem.CheckValue())
returnList.Add(CurrentItem);
});
if (progressList != null)
{
progressList.Report(returnList);
Thread.Sleep(1000);
}
}
}
static internal void RegisterLister(ValueListener Listner)
{
ListenList.Add(Listner);
}
static internal void UnRegisterLister(ValueListener Listner)
{
ListenList.Remove(Listner);
}
}
}
}
internal class ValueListener
{
public event EventHandler<ValueChangeEventArgs> Changed;
public string FullPath { get; }
public object Value { get; private set; }
private object oldObjectValue;
internal ValueListener(string Path) // update prio is a enum
{
this.FullPath = Path;
CommManager.ValueListenManager.RegisterLister(this); // here i register into the ListenList above
}
~ValueListener()
{
CommManager.ValueListenManager.UnRegisterLister(this); // de-register after destruction
}
// Check for value changes
public bool CheckValue()
{
var SmallTest = new Random();
Value = SmallTest.Next(1, 5);
if (Value != null && !Value.Equals(oldObjectValue))
return true;
return false;
}
// Check for value change, here is where i trigger updates on the UI
public void TriggerChange()
{
if (Changed != null)
Changed.Invoke(this, new ValueChangeEventArgs(Value, oldObjectValue));
oldObjectValue = Value;
}
}
public class ValueChangeEventArgs : EventArgs
{
public ValueChangeEventArgs(object Value, object OldValue)
{ }
}
This should work alright for you. It takes advantage of Microsoft TPL Dataflow, which is available as a nuget package.