You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#:事件多次触发时如何仅执行一次计数逻辑?

批量勾选树形数据点时的性能优化问题

问题场景

项目中通过DatapointInstance类存储树形结构数据,UI复选框绑定RestoreVar属性,勾选父节点时会递归设置所有子节点的RestoreVar值。但每个子节点都会触发RestoreVarChanged事件,导致主类中统计勾选数量的Count方法被频繁调用(百万级数据场景下会执行百万次),性能极差。

现有代码

DatapointInstance类

public class DatapointInstance : INotifyPropertyChanged
{
    private bool restoreVar;
    private List<DatapointInstance> subVariables;
    public event PropertyChangedEventHandler PropertyChanged;

    public event EventHandler RestoreVarChanged;

    public string Name{ get; set; }
    public string Value { get; set; }
    // 其他属性

    public bool RestoreVar // 绑定UI复选框
    {
        get { return restoreVar; }
        set { 
            if (restoreVar != value)
            { 
                restoreVar = value;
                OnPropertyChanged(nameof(RestoreVar));
                OnRestoreVarChanged();   
            } 
        }
    }
    public List<DatapointInstance> SubVariables // 树形结构子节点
    {
        get { return subVariables; }
        set { 
            if (subVariables != value) 
            { 
                subVariables = value; 
                OnPropertyChanged(nameof(SubVariables)); 
            } 
        }
    }

    protected virtual void OnRestoreVarChanged()
    {
        RestoreVarChanged?.Invoke(this, EventArgs.Empty);
    }

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        foreach (var item in subVariables)
        {
            item.RestoreVar = RestoreVar;
        }
    }
}

主类事件处理代码

private void SomeCheckboxChaneged(object sender, EventArgs e)
{
    UI_Counter = Count(ListofDatapoints); // 统计所有勾选的数据点数量
    NotifyPropertyChanged("UI_Counter");
}

解决方案

1. 批量操作时禁用子节点事件触发

在DatapointInstance中添加批量更新标志,批量设置子节点时跳过事件触发,仅在父节点批量操作完成后触发一次事件:

public class DatapointInstance : INotifyPropertyChanged
{
    private bool restoreVar;
    private List<DatapointInstance> subVariables;
    private bool isBatchUpdating; // 新增批量更新标志

    // ... 原有属性、事件不变

    public bool RestoreVar
    {
        get { return restoreVar; }
        set { 
            if (restoreVar != value)
            { 
                restoreVar = value;
                OnPropertyChanged(nameof(RestoreVar));
                // 仅非批量更新状态下触发事件
                if (!isBatchUpdating)
                {
                    OnRestoreVarChanged();
                }
            } 
        }
    }

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        
        if (propertyName == nameof(RestoreVar))
        {
            isBatchUpdating = true; // 开启批量更新模式
            foreach (var item in subVariables)
            {
                item.RestoreVar = RestoreVar;
            }
            isBatchUpdating = false; // 关闭批量更新模式
            // 批量操作完成后,父节点主动触发一次事件
            OnRestoreVarChanged();
        }
    }
}

此方案下,父节点勾选时仅会触发一次RestoreVarChanged事件,主类只需执行一次统计,性能直接优化。

2. 轻量延迟执行(替代定时器)

如果无法修改DatapointInstance类,可在主类中用Task.Delay结合取消令牌合并短时间内的多次事件,仅执行一次统计:

private CancellationTokenSource _delayCts;

private async void SomeCheckboxChaneged(object sender, EventArgs e)
{
    // 取消之前未执行的延迟任务
    _delayCts?.Cancel();
    _delayCts = new CancellationTokenSource();
    
    try
    {
        // 延迟100ms(可根据需求调整),等待批量事件结束
        await Task.Delay(100, _delayCts.Token);
        if (!_delayCts.IsCancellationRequested)
        {
            UI_Counter = Count(ListofDatapoints);
            NotifyPropertyChanged("UI_Counter");
        }
    }
    catch (TaskCanceledException)
    {
        // 忽略取消异常,无需处理
    }
}

该方案无需修改子类,通过合并短时间内的多次事件触发,避免重复执行统计逻辑。


内容的提问来源于stack exchange,提问作者Tom

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 17:23:31