以下是我寫的遇到問題的程式的程式碼片段Form1.cs的內容
完整的遇到問題之專案請到這裡下載
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Timers;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
MyLabelController Controller = new MyLabelController();
public Form1()
{
InitializeComponent();
}
public void label1_Hello()
{
label1.Text = "Hello";
}
public void label1_World()
{
label1.Text = "World";
}
private void button1_Click(object sender, EventArgs e)
{
Controller.HelloWorld(this);
}
}
public class MyLabelController
{
Form1 Parent;
public void HelloWorld(Form1 target)
{
Parent=target;
Parent.label1_Hello();
System.Timers.Timer t = new System.Timers.Timer(3000);
t.Elapsed += this.Next;
t.Enabled = true;
}
private void Next(Object obj, ElapsedEventArgs e)
{
Parent.label1_World();
}
}
}
這隻程式主要是透過按下按鈕,然後把label的值改成Hello,並在三秒後把值改成World,但是在這裡並不是由Form1對label的值進行修改,而是由Form1的成員Controller來對label的值進行修改,並且啟動Controller中的Timer來計時,並觸發二度改寫文字的事件,成員Controller的類別是屬於寫在同一個Namespace WindowsFormsApplication1的類別MyLabelController,至於為何我要這樣用? 只是單純想測試可不可以寫一個控制用成員,負責管理其他UI類的成員,只需要操控此控制用成員,此控制用成員能幫你去管理你的所有UI類成員,也就是當有數百個label類的UI成員的時候,成員Controller能夠依照你對它的操控,幫你去管理其他的label類的UI成員。
程式執行畫面大概像這樣:
而按下按鈕,之後會順利的顯示Hello,但是過了三秒後再跳出World的時候,就發生錯誤了
以上就是遇到的問題,或許大家會覺得我這種寫法脫褲子放屁,遇到問題活該,不過由於我剛學C#沒有很久,之前都是學Gnu的C與C++,所以目前還是在學習階段,所以我當遇到問題是學習,既然都遇到問題了,那至少要先把這個問題解決,再以別的方法實踐相同功能,作為C#的學習。
於是後來查了資料,此種問題,是因為我在class MyLabelController中宣告的Timers事件,實際上已經與Form1始於不同的執行續, 但是在Form1呼叫Controller的方法HelloWorld時,是以Form1的執行續互叫來執行的,所以顯示Hello時沒遇到錯誤,直到Controller的Timers事件Elapsed時,此時由於是由MyLabelController的事件處理觸發的事件,故執行續與Form1的執行續不相同,而為了安全起見,兩個不同執行續A、B,A無法控制位於B中的UI物件(控制項),B也無法無法控制位於A中的UI物件(控制項),所以發生了System.InvalidOperationException,造成錯誤。至於要如何修改呢? 在這裡我們必須用到委派(dalegate)的方式來處理
委派如同字面意思,在這裡就是讓Controller委託 Form1去做label1_World()這件事情,由於 Form1本身就是label1UI物件(控制項)得擁有者,由Controller委託 Form1來做,自然就不會遇到A無法控制位於B中的UI物件(控制項)的問題,至於要怎麼改呢? 程式碼如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Timers;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
MyLabelController Controller = new MyLabelController();
public delegate void mydalegate();
public mydalegate md;
public Form1()
{
InitializeComponent();
md = new mydalegate(label1_World);
}
public void label1_Hello()
{
label1.Text = "Hello";
}
public void label1_World()
{
label1.Text = "World";
}
private void button1_Click(object sender, EventArgs e)
{
Controller.HelloWorld(this);
}
}
public class MyLabelController
{
Form1 Parent;
public void HelloWorld(Form1 target)
{
Parent=target;
Parent.label1_Hello();
System.Timers.Timer t = new System.Timers.Timer(3000);
t.Elapsed += this.Next;
t.Enabled = true;
}
private void Next(Object obj, ElapsedEventArgs e)
{
//Parent.label1_World();
Parent.Invoke(Parent.md);
}
}
}
解釋一下下列的程式碼:public delegate void mydalegate(); 由於我們要委託的對象方法為
public void label1_World(); 是屬於void,並且沒有參數傳入,所以這裡要把 mydalegate 定義成這樣:public delegate void mydalegate();。
接下來,建立委派
public mydalegate md; 並且在Form1的建構子,明確指定此委派的對象為方法為 label1_World;
public Form1()
{
InitializeComponent();
md = new mydalegate(label1_World);
}
最後,只要把Next中的程式,修改為
private void Next(Object obj, ElapsedEventArgs e)
{
//Parent.label1_World();
Parent.Invoke(Parent.md); //委派Form1去執行md這個委派
}
就能順利執行了,以下為程式執行結果改寫後的程式碼,請點這裡下載
GOOD 要的就是你
回覆刪除幫非常大的忙!!感謝!!
回覆刪除感謝~~
回覆刪除