我需要在我的程序中創建類以啓動一系列事件以在文本框中寫入文本。 我知道這些類不應該知道表單。怎麼做?考慮到我將在另一個線程上安裝類的事實。在anoter類的文本框中寫入(在另一個線程上)
我已經嘗試了一個接口,它連接類並使用ref參數在窗體上創建方法。
* 更新: *你們都誤會了我 - 我在談論的事件並不是在進步。我需要的只是添加文本到另一個類的文本框。我添加了「事件鏈」來從simila問題中定義它,他們試圖直接從課堂上改變文本。抱歉。
我需要在我的程序中創建類以啓動一系列事件以在文本框中寫入文本。 我知道這些類不應該知道表單。怎麼做?考慮到我將在另一個線程上安裝類的事實。在anoter類的文本框中寫入(在另一個線程上)
我已經嘗試了一個接口,它連接類並使用ref參數在窗體上創建方法。
* 更新: *你們都誤會了我 - 我在談論的事件並不是在進步。我需要的只是添加文本到另一個類的文本框。我添加了「事件鏈」來從simila問題中定義它,他們試圖直接從課堂上改變文本。抱歉。
如果不瞭解您的應用程序,我會建議您需要的是調用表單處理的類中的事件。會發生什麼是這樣的:
你需要添加一些定義:
public delegate void FinishedEventHandler(object sender, string ValueToReturn);
public event FinishedEventHandler Finished;
首先是與事件的簽名的委託。按照慣例,第一個參數總是對類本身的實例的引用,其餘的是你想要返回的值。第二個是實際事件。現在
,在做任何處理類做了我們需要提高在適當的時候對事件的函數:
void DoSomething()
{
.
.
.
if(Finished!=null) Finished(this, "some value");
}
IF子句用於確保有人實際上是處理我們的事件,否則我們可能會得到一個異常。
現在讓我們來看看錶單。我們需要添加一個處理事件的函數。它需要與我們之前定義的委託具有相同的簽名。在這一功能,我們做任何變化,我們需要在表格中的值的光中,我們得到的:
private void FinishedEventHandler(object sender, string ValueToReturn)
{
TextBox1.Text = ValueToReturn;
}
現在,我們已經準備好使用我們剛剛創建的所有管道。首先我們將處理程序添加到事件中,然後我們可以調用該類的處理函數。
MyClass.Finished += FinishedEventHandler;
MyClass.DoSomething();
這裏有一個更詳細的教程:
http://msdn.microsoft.com/en-us/library/aa645739(v=vs.71).aspx
這裏有兩個可能的選擇:
「其它類」需要儘快,因爲它是「完成」更新文本框這是工作。如果是這種情況,它不應該知道窗體,任何文本框,界面,什麼都不知道。它應該只是返回值並讓表單使用該返回值來設置文本框,或者做任何事情。
在大多數情況下,這是你想要做的,而且它是解決這類問題的最簡單和最有效的手段。如果你不需要,不要使用更復雜的東西。
如果信息在任務完成時沒有發生,但是通過週期性間隔,則可以使用Progress
類與IProgress
接口。
讓Form
創建實例:Progress<string> progress = new Progress<string>();
。有形式附加該實例的事件處理程序。請注意,Progress
實例將「捕獲」當前的同步上下文,這是說它在UI線程中運行的奇特方式。這是可以做到像這樣:
progress.ProgressChanged += (_, data) => textBox1.Text = data;
然後纔有其他類接受IProgress<string>
實例,並定期調用:
progress.Report(someString);
如果你需要預先4.5實施Progress
和IProgress
,這裏是一個將在.NET 3.5+中編譯和運行的實現:
public interface IProgress<T>
{
void Report(T data);
}
public class Progress<T> : IProgress<T>
{
SynchronizationContext context;
public Progress()
{
context = SynchronizationContext.Current
?? new SynchronizationContext();
}
public Progress(Action<T> action)
: this()
{
ProgressReported += action;
}
public event Action<T> ProgressReported;
void IProgress<T>.Report(T data)
{
var action = ProgressReported;
if (action != null)
{
context.Post(arg => action((T)arg), data);
}
}
}
請注意,[IProgress](http://msdn.microsoft.com/zh-cn/library/hh138298.aspx)是.NET 4.5的新增功能,因此如果您的目標是早期的框架,它將不可用。 – 2013-02-08 20:53:42
@ScottChamberlain確實,雖然它不需要任何新語言功能;您可以在幾十行代碼中編寫自己的'Progress'類/接口。 – Servy 2013-02-08 20:54:43
非常真實,我只是不希望操作系統在無法找到界面的情況下抓住加爾。 – 2013-02-08 21:05:42
其實所有這些都可以用三行代碼來表示,這當然可以在簡短的答案範圍內完成。第6步沒有與之相關的代碼,第2步和第4步是真實的,你可以指望OP自己弄清楚;他們不需要在你的答案中。儘管如此,這確實是一個很好的方法。 – Servy 2013-02-08 20:47:42
系統沒有提到的一件事是你正在做跨線程通信,你需要在窗體中的事件處理函數內部做一個'Invoke'。 – 2013-02-08 20:52:10
1)定義事件時,不需要定義自己的委託類型。只需使用'Action' /'Func',或者如果您真的覺得有義務使用基於事件的處理程序,則可以使用'EventHandler'。 2)爲分配事件處理程序,您可以使用lambda,這對於這些真正的小事件更有效,儘管可以始終使用命名方法處理不重要的處理程序。 –
Servy
2013-02-08 21:10:06