为外部库的属性值更改创建事件处理程序

时间:2017-03-02 05:26:52

标签: c# .net-4.6.1

我正在使用具有根据特定事件而更改的属性的外部库。有时值会快速变化(但仅以1到2之间的增量)。我想创建一个事件处理程序来检测值是否已更改以及是否更改将检索值作为等式的一部分,以将表单移动到屏幕上的某个点。我目前正在使用计时器:

private var foo;

public Form1()
{
   this.InitializeComponent();

   this.foo = new Foo();
   this.DesktopLocation = new Point(foo.Property1 + 100, 500);

   Timer timer = new Timer();
   timer.Interval = 1;
   timer.Tick += new EventHandler(this.Timer_Tick);
   timer.Start();
}

private void Timer_Tick(object sender, EventArgs e)
{
   this.DesktopLocation = new Point(this.foo.Property1 + 100, 500);
}

我以Trigger a custom event for an "external" value change为基础,但我希望有更好的解决方案,因为如果foo.Property1在短时间内多次改变,表格会落后于预期的点并闪烁。我试图让表单遵循类似于用户使用鼠标移动表单的点。在Timer之前,我在带有递归的单独Thread上使用了while循环:

       private void CheckFoo()
       {
            while (!this.Created)
            {
            }

            if (new Point(this.foo.Property1 + 100, 500) != this.DesktopLocation)
            {
                this.Invoke(new Action(() =>
                {
                    this.DesktopLocation = new Point(this.foo.Property1 + 100, 500);
                }));
            }

            while (this.DesktopLocation == new Point(this.foo.Property1 + 100, 500) && this.ContinueLoop)
            {
            }

            if (this.ContinueLoop == false)
            {
                return;
            }
            else
            {
                this.CheckFoo();
            }
       }

上述方法在视觉上按预期工作约30秒,但随后在代码中的不同位置与StackOverflowException崩溃,通常在this.DesktopLocation = new Point(this.foo.Property1 + 100, 500);但有时在其他地方(我无法不幸的是复制了另一个位置)。我在这里阅读了StackOverflowExceptions:https://www.dotnetperls.com/stackoverflowexception,似乎是因为我使用了递归循环,所以我假设我不能使用上面的方法。有没有办法在没有视觉问题(或例外)的情况下实现这一目标?

1 个答案:

答案 0 :(得分:0)

  

在Timer之前,我在带有递归的单独Thread上使用了while循环:

为什么呢?为什么递归?

在我看来,你的方法应该是这样编写的:

private void CheckFoo()
{
    // It would be better to just not start the thread that
    // runs this method until the "Created" flag is set, rather
    // that having this busy loop to wait. At the very least, there
    // are better mechanisms for waiting than a loop like this.
    while (!this.Created)
    {
    }

    while (this.ContinueLoop)
    {
        if (new Point(this.foo.Property1 + 100, 500) != this.DesktopLocation)
        {
            this.Invoke(new Action(() =>
            {
                this.DesktopLocation = new Point(this.foo.Property1 + 100, 500);
            }));
        }
    }
}

现在,这种民意调查并不理想。至少,您应该创建一个专用线程并将线程优先级设置为不高于BelowNormal和/或在Thread.Sleep(1)循环内包含对while的调用(强制该线程)屈服于任何其他准备好的线程)。但是,如果您真的必须以此频率监视DLL的值,并且DLL本身实际上不提供轮询以外的机制,以便您收到有关值更改的通知,您可能会遇到代码那样的。

还要记住,拨打Invoke()的费用很高。即使有了上述情况,如果价值以非常高的频率发生变化,您仍可能无法以您希望的速度看到更新。