首页 > 解决方案 > 如何在每个 Timer 滴答中检查 propertychanged 一次?

问题描述

我使用 2 个计时器,1 个每秒检查我所有的 Citect 标记是否有更改的值。另一个是 TCP 连接的 KeepAlive 计时器。

这就是我如何称呼计时器:

Timer timer = new Timer(ctApiCtrl.CheckUpdateAllInputTags, "updatetags", 1000, 1000);
Timer timer2 = new Timer(mepCtrl.KeepAlive, "test", 3000, 3000);

现在由于现有系统如何协同工作的性质是写入和读取 PLC/DSK 标签。因此,如果我的服务想要检测这些更改,它需要定期“轮询”或检查这些值。

这是这些标签来自的类:

        public class TagWithValue : INotifyPropertyChanged
        {
            public string  TagName { get; set; }
            private string tagValue;
            public TagCategory TagCategory { get; set; }
            public string TagValue
            {
                
                get { return tagValue; }
                set 
                { 
                    if(tagValue != value)
                    {
                        tagValue = value;
                        RaisePropertyChanged();
                    }
                }
            }
            public event PropertyChangedEventHandler PropertyChanged;

            private void RaisePropertyChanged([CallerMemberName] string prop = "") 
            {
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs(prop));
            }
        }

因此,当属性TagValue更改时,它会检测到它并触发 x。

        public void CheckUpdateAllInputTags(object objectInfo)
        {
            VDGSenseController.Authenticate();
            if (listOfTags.Video == null || listOfTags.Audio == null)
            {
                Logger.Info("Empty Tag list , reinitliazing all tags");
                InitiliazeAllTags();
            }
            
            foreach (var tag in Tags)
            {
                try
                {
                    var value = TagRead(tag.TagName); //read Tag value
                    tag.TagValue = value;
                    tag.PropertyChanged += d_PropertyChanged;
                }
                catch (Exception ex)
                {
                    Logger.Warn(ex,"Importing tag unsuccesfull");
                    continue;
                }
            }
            Tags = Tags.Where(t => !string.IsNullOrWhiteSpace(t.TagValue)).Distinct().ToList();
        }

这就是这个片段的问题。

private void d_PropertyChanged(object sender,PropertyChangedEventArgs e)
{           
     //trigger wanneer prop value is changed
     var tagchanged = (CtModel.TagWithValue)sender;
            
    Logger.Info($"Tag: {tagchanged.TagName} with value: {tagchanged.TagValue} has changed.");
}

我对这段代码的问题是它在同一个计时器滴答声中多次触发 propertychanged 方法。

请注意包含标记的日志记录:DK_OM_2A

计时器记录

我怎样才能改变它,使它只在每个计时器滴答声中触发一次?

标签: c#timerwindows-servicesinotifypropertychangedpolling

解决方案


我通过以不同的方法从 propertychanged 中移动逻辑来修复它,在新代码中它是这样的:

    private void d_PropertyChanged(object sender,PropertyChangedEventArgs e)
    {
        
        //trigger wanneer prop value is changed
        var tagchanged = (CtModel.TagWithValue)sender;
        tagsWithChangedValue.Add(tagchanged);
        tagsWithChangedValue = tagsWithChangedValue.Distinct().ToList();

    }


#region UpdateTagsPropertyChanged
    public void UpdateTagsPropertyChanged(List<CtModel.TagWithValue> listofchangedtags)
    {
        if(listofchangedtags.Count == 0)
        {
            return; // if list is empty, go back
        }
        foreach(var tagchanged in listofchangedtags)
        {
            logger.Info($"Tag: {tagchanged.TagName} with value: {tagchanged.TagValue} has changed.");
            switch (tagchanged.TagName)
            {
                default:
                    break;
            }
        }
        tagsWithChangedValue.Clear(); //clears list for the next cycle
    }
    #endregion

推荐阅读