How to avoid recalculations while properties are set ?

c#chris

Active member
Joined
Dec 10, 2024
Messages
29
Programming Experience
1-3
Hello, I use properties as follows:

C#:
private int _deltapocminvalue = -1;
    [Range(-1, int.MaxValue)]
    [Display(Name = "min. Value")]
    [Description("-1 = feature off, absolute values checked, no values < -1 allowed")]
    public int DeltaPocMinValue
    {
        get => _deltapocminvalue;
        set
        {
            object before = DeltaPocMinValue;
            if (_deltapocminvalue == value) return;
            if (value != -1) DeltaPocValue = CHECKIGNORE.Check;
            else DeltaPocValue = CHECKIGNORE.Ignore;
            _deltapocminvalue = value;
            OnPropertyChanged(new PropertyValueChangedEventArgs(nameof(DeltaPocMinValue), before, DeltaPocMinValue));
        }
    }


The user can enter numbers according his wishes, he could also use the wheel of the mouse to find hins number or the arrow buttons of the keyboard.

Problem:

Everytime user scrolls through his numbers the event is triggered for each number in between, which leads to unnecessary calculations.

Example:

User enters 32 -> First calculations for 3 are done then for 32.
User increases numbers via mousewheel1 2 3 4 5 6 -> 6 events are fired, even if the user only wants to set the number finally to 6.

Question:

Is there a way to avoid this so that an event is only fired if the fiel contains the final number.
Could this be e.g. synchronised with the release of the mouse button e.g. -> tried it but did not work.
 
You need to help us out a bit more... What UI framework are you using? WinForms, WebForms, ASP.NET MVC, WPF, MAUI.NET, etc.?

In general, the strategy is to not directly bind to the UI. Instead detect when the UI changes and set a timer. If the UI changes again before the UI expires, then reset the timer. When the timer expires, then finally set the property.
 
Hello, unfortunately I do nou know which Framework it is. The only information I have is a relatively poor API descrition:

My projectfile for the plugindll starts as follows:

C#:
<PropertyGroup>
    <TargetFramework>net8.0-windows</TargetFramework>
    <Nullable>enable</Nullable>
    <UseWPF>true</UseWPF>
    <UseWindowsForms>true</UseWindowsForms>
    <AssemblyVersion>1.2.7.0</AssemblyVersion>
    <FileVersion>1.2.7.0</FileVersion>
  </PropertyGroup>

The member function "RecalculateValues()" initiates a new calculation and takes every change of a property caused by the user into account.
If I change properties via UI which are located in subclasses, the member funktion OnPropertyChanged is called as can be seen above.
This causes an event that again calls "RecalculateValues()" in the plugin dll upper level.

This recalculation takes relatively long depending on the data (chart bars). What I need to avoid ist to call "RecalculateValues()"
unnessesarily every time before the user reached his final value.
 
The line:
C#:
<UseWindowsForms>true</UseWindowsForms>
Suggests that you are using WinForms, but that's just a guess.

So you are not in control of the UI? Your code is just a plugin that runs in some other application? Is this application different from the other other thread where you are trying to serialize/deserialize settings as JSON?
 
Hi:

So you are not in control of the UI? Yes correct. The properties I define appear in a dialog of that application but I have no access to its code.
Your code is just a plugin that runs in some other application? Yes. My code is a dll located in a special directors of the other applications. All dlls in this directory are loaded during the start of the app.
Is this application different from the other other thread where you are trying to serialize/deserialize settings as JSON? I guess yes. The applications runs totally independent from my dll.
The only interface I have to the UI are the public properties that will be visualized in the apps UI.
 

Attachments

  • exampleProperies.JPG
    exampleProperies.JPG
    47.3 KB · Views: 2
I see...

Does the main application expect to get the property changed notification immediately after it sets your property?

How tolerant is the main application of receiving delayed property changed notifications?

Can it accept property change notifications that come in from another thread?
 
I added an example of the property window (main app) in #5. These properties are defined in my dll and become visible in the main apps dialog called "Indicator Settings"
after the dll has been loaded via the main app.

Does the main application expect to get the property changed notification immediately after it sets your property?
When I change a property, e.g. increasing numbers, I see this immediately in the UI without calling e.g. "RaisePropertyChanged".

How tolerant is the main application of receiving delayed property changed notifications?
At least I do not call or send any "RaisePropertyChanged" notifications.
So maybe this is done somewhere in the background.

This is the BaseClass I inherited:

C#:
namespace ATAS.Indicators
{
    [DataContract]
    [DefaultMember("Item")]
    public abstract class BaseIndicator : ChartObject, INotifyPropertyChanged, IDisposable, INotifyPanelPropertyChanged
    {
        protected readonly List<Indicator> UsedIndicators;

        protected BaseIndicator(bool useCandles = false);

        public decimal this[int index] { get; protected set; }

        protected static bool UseProfiling { get; set; }
        protected static PerformanceDiagnoser? PerformanceDiagnoser { get; }
        [Display(ResourceType = typeof(object), Name = "SourceDataSeries", GroupName = "Common", Description = "SourceDescription", Order = 10)]
        [IgnoreDataMember]
        [JsonIgnore]
        public IDataSeries<decimal>? SourceDataSeries { get; set; }
        [Browsable(false)]
        [IgnoreDataMember]
        public int CurrentBar { get; }
        [Browsable(false)]
        [IgnoreDataMember]
        [JsonIgnore]
        public bool UseCandles { get; }
        [Browsable(false)]
        public bool IsVerticalIndicator { get; set; }
        [DataMember]
        [Display(ResourceType = typeof(object), Name = "Panel", GroupName = "Drawing", Description = "PanelDescription", Order = 0)]
        public string Panel { get; set; }
        [Display(ResourceType = typeof(object), GroupName = "Lines")]
        [IgnoreDataMember]
        [JsonIgnore]
        public List<LineSeries> LineSeries { get; }
        [Display(ResourceType = typeof(object), GroupName = "Drawing")]
        [IgnoreDataMember]
        public List<IDataSeries> DataSeries { get; }
        [Browsable(false)]
        [IgnoreDataMember]
        [JsonIgnore]
        public bool IsDisposed { get; set; }
        [Browsable(false)]
        public string Name { get; set; }

        public event PropertyChangedEventHandler PropertyChanged;
        public event PropertyChangedEventHandler PanelPropertyChanged;
        public event Action<int> BarValueChanged;

        protected static PerfCounter MeasurePerformance(string name);
        public virtual void Dispose();
        public override string ToString();
        protected void Add(Indicator indicator);
        protected virtual void Calculate(int bar, decimal value);
        protected void Clear();
        protected abstract void OnCalculate(int bar, decimal value);
        protected virtual void OnDispose();
        protected virtual void OnFinishRecalculate();
        protected virtual void OnInitialize();
        protected virtual void OnRecalculate();
        protected virtual void OnSourceChanged();
        protected override void OnVisibleChanged();
        protected void RaiseBarValueChanged(int bar);
        protected void RaisePanelPropertyChanged(string name);
        protected void RaisePropertyChanged(string propertyName);
        protected void RaisePropertyChanged(object sender, PropertyChangedEventArgs e);
        protected virtual void RecalculateValues();
    }
}

I only have this information, no code, poor description.

What I must do if a property changed is to call "RecalculateValues" which updates the chart in the main app based on my property amendments.
This is the bottleneck because for each property change the whole recalc is started.

Can it accept property change notifications that come in from another thread?
There is a function called: RaisePanelPropertyChanged(string name); but I did not see any effects when I use it, the ui updates also without it.
 
Assuming that the main application can tolerate late updates, you can have your property set a (WinForms) timer when the value changes. If the value changes again before the timer expires, reset the timer. Once the timer expires, do the recalculate and property change notifications. I think that WinForms timers will let you do the most without having to deal with any cross threading issues.

Assuming that the main application can tolerate cross thread updates, then you can do the recalculations in on a background worker thread. Yes, you'll end up doing a whole bunch of expensive calculations, but at least they won't be blocking the main UI thread making the main application unresponsive.

Beware that you might run into a race condition where the background workers might finish in a different order that you started them in. The way around that would be to queue jobs for a single background worker to read off the queue and recalculate as needed. Perhaps, you can cheat a bit and see if there is more than one value in the queue, and just skip those and go straight to the last item in the queue. That would minimize the number of expensive recalculations.
 
Back
Top Bottom