2017-03-02 70 views
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改變多次在很短的時間跨度。我試圖讓窗體遵循類似於用戶使用鼠標移動窗體的點。定時器之前,我使用的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,它似乎是因爲我使用了遞歸循環,所以我假設我不能使用上面的方法。有沒有什麼方法可以在沒有視覺問題(或例外)的情況下實現?

+0

這與您的第三方類有關,繼承,包裝,創建代理或其他任何 – AlirezaJ

+0

@AlirezaJ我不明白請詳細說明。有沒有你連接的問題或什麼? 「這是'表明一個聲明,並且以下'與'有關'表明你想要鏈接一個問題。 – JordanZeotni

回答

0

我用遞歸一個單獨的線程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和/或在while循環內包含對Thread.Sleep(1)的調用(強制線程屈服於任何其他就緒線程)。但是如果你真的需要在這個頻率上監視DLL的值,並且DLL本身並沒有提供除輪詢以外的其他機制來通知你這個值發生了變化,你可能會被這樣的代碼困住。

也請記住,致電Invoke()是昂貴的。即使有了上述情況,如果價值以非常高的頻率變化,您仍然不會按照您希望的速度看到更新。

+0

我完全刪除了'while(!this.Created){}',並且應用程序運行良好,但是會有更好的方法來處理這個問題,以防止表單未完全加載導致InvalidOperationException? – JordanZeotni

+0

_「但是會有更好的方法來處理這個問題嗎?」 - 如果沒有更多的上下文,無法肯定地說。但就像我在上面的代碼註釋中所寫的那樣,只有在知道它是安全的之前,才能啓動線程。例如。將該代碼放入窗體的「顯示」事件的事件處理程序中。 –

相關問題