我正在做一个项目并遇到以下问题。我有一个主类,它读取 xml 并将其显示在 UI 中。对于每个数据点,它都会实例化另一个类的对象,该类保存所有信息。数据保存在一个列表中,该列表具有嵌套列表直至数据点。它就像一个树结构。这是保存信息的子类:
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; }
//some more properties
public bool RestoreVar //Checkbox
{
get { return restoreVar; }
set { if (restoreVar != value)
{ restoreVar = value;
OnPropertyChanged(nameof(RestoreVar));
OnRestoreVarChanged(); } }
}
public List<DatapointInstance> SubVariables //This one is to make the tree structure possible
{
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;
}
}
}
当选中 UI 中的复选框时,会触发一个事件来检查所有底层数据点(OnPropertyChanged 事件)。
我还有一个计数器,可以计算并显示检查的数据点的数量。问题就从这里开始了。我触发事件 OnRestoreVarChanged 来告诉主类发生了一些变化,它应该重新计算变量的数量并更新 UI。但由于我还检查每个子数据点,它经常触发。 如果我有大约一百万个数据点并检查最上面的数据点,它会将所有变量重新计数一百万次,这并不是很好的性能虎钳(显然)。
这是我的事件,它监听每个实例的事件:
private void SomeCheckboxChaneged(object sender, EventArgs e)
{
UI_Counter = Count(ListofDatapoints); //returns the amount of checked datapoints
NotifyPropertyChanged("UI_Counter");
}
这原则上是可行的,但正如我所说,这是性能非常糟糕的虎钳。 我考虑过使用一个计时器,每次触发事件时都会重新启动,并在最后一个事件结束后启动计数器一次。但我讨厌在 C# 中使用计时器。你还有其他选择吗?还是我对计时器的恐惧有点过大?
所以我用计时器尝试了一下,效果非常完美。感谢@Fildor 的建议。 每次选中复选框和子复选框时都会触发 SomeCheckboxChanged 事件。它每次都会重新启动计时器,并且仅当计时器到时才会执行计数逻辑并更新 UI。
private System.Timers.Timer timer;
private bool isTimerStarted = false;
private void SomeCheckboxChaneged(object sender, EventArgs e)
{
// Check if the timer has already been started
if (!isTimerStarted)
{
// If not, create and start the timer
timer = new System.Timers.Timer();
timer.Interval = 50;
timer.Elapsed += OnTimerElapsed;
timer.Start();
isTimerStarted = true;
}
else
{
// If the timer is already started, reset it
timer.Stop();
timer.Start();
}
private void OnTimerElapsed(object sender, ElapsedEventArgs e)
{
UI_Counter = Count(ListofDatapoints); //returns the amount of checked datapoints
NotifyPropertyChanged("UI_Counter");
// Reset the flag
isTimerStarted = false;
// Stop and dispose the timer
if (timer != null)
{
timer.Stop();
timer.Dispose();
}
}