Tôi đang xây dựng thành phần không trực quan trong .Net 2.0. Thành phần này sử dụng một ổ cắm không đồng bộ (BeginReceive, EndReceive, vv). Gọi lại không đồng bộ được gọi trong ngữ cảnh của một chuỗi công nhân được tạo ra bởi thời gian chạy. Người dùng thành phần không phải lo lắng về đa luồng (Đây là mục tiêu chính, những gì tôi muốn)Sự kiện cháy từ thành phần Không đồng bộ trong chuỗi giao diện người dùng
Người dùng thành phần có thể tạo thành phần không trực quan của tôi trong bất kỳ chủ đề nào (chuỗi giao diện người dùng chỉ là một chủ đề chung cho đơn giản Các ứng dụng nghiêm trọng hơn có thể tạo thành phần trong một chuỗi công nhân tùy ý). Thành phần kích hoạt các sự kiện như "SessionConnected" hoặc "DataAvailable".
Vấn đề: vì các cuộc gọi lại Async và các sự kiện được nêu trong đó trình xử lý sự kiện được thực hiện trong ngữ cảnh chuỗi công nhân. Tôi muốn sử dụng một lớp trung gian buộc trình xử lý sự kiện thực thi trong ngữ cảnh của chuỗi tạo thành phần ở vị trí đầu tiên.
Ví dụ mã (rút gọn từ ngoại lệ xử lý vv ...)
/// <summary>
/// Occurs when the connection is ended
/// </summary>
/// <param name="ar">The IAsyncResult to read the information from</param>
private void EndConnect(IAsyncResult ar)
{
// pass connection status with event
this.Socket.EndConnect(ar);
this.Stream = new NetworkStream(this.Socket);
// -- FIRE CONNECTED EVENT HERE --
// Setup Receive Callback
this.Receive();
}
/// <summary>
/// Occurs when data receive is done; when 0 bytes were received we can assume the connection was closed so we should disconnect
/// </summary>
/// <param name="ar">The IAsyncResult that was used by BeginRead</param>
private void EndReceive(IAsyncResult ar)
{
int nBytes;
nBytes = this.Stream.EndRead(ar);
if (nBytes > 0)
{
// -- FIRE RECEIVED DATA EVENT HERE --
// Setup next Receive Callback
if (this.Connected)
this.Receive();
}
else
{
this.Disconnect();
}
}
Do tính chất của Async ổ tất cả các ứng dụng sử dụng thành phần của tôi được rải rác với "Nếu (this.InvokeRequired) {... "và tất cả những gì tôi muốn là người dùng có thể sử dụng thành phần của tôi không phải lo lắng như một loại trình đơn thả xuống.
Vì vậy, làm cách nào để tôi nâng cao sự kiện mà không yêu cầu người dùng kiểm tra InvokeRequired (hoặc, đặt khác, làm cách nào để buộc các sự kiện được nêu trong cùng một luồng với chuỗi bắt đầu sự kiện ở vị trí đầu tiên)?
Tôi đã đọc nội dung về AsyncOperation, BackgroundWorkers, SynchronizingObjects, AsyncCallbacks và hàng tấn công cụ khác nhưng tất cả đều làm cho đầu của tôi quay.
tôi đã đưa ra với điều này, chắc chắn vụng về, "giải pháp" nhưng có vẻ như thất bại trong một số trường hợp (khi thành phần của tôi được gọi từ một dự án WinForms qua một lớp tĩnh ví dụ)
/// <summary>
/// Raises an event, ensuring BeginInvoke is called for controls that require invoke
/// </summary>
/// <param name="eventDelegate"></param>
/// <param name="args"></param>
/// <remarks>http://www.eggheadcafe.com/articles/20060727.asp</remarks>
protected void RaiseEvent(Delegate eventDelegate, object[] args)
{
if (eventDelegate != null)
{
try
{
Control ed = eventDelegate.Target as Control;
if ((ed != null) && (ed.InvokeRequired))
ed.Invoke(eventDelegate, args);
else
eventDelegate.DynamicInvoke(args);
}
catch (Exception ex)
{
Console.WriteLine(ex.GetType());
Console.WriteLine(ex.Message);
//Swallow
}
}
}
Bất kỳ giúp đỡ sẽ được đánh giá cao. Cảm ơn trước!
EDIT: Theo this thread đặt cược tốt nhất của tôi là sử dụng SyncrhonizationContext.Post nhưng tôi không thể xem cách áp dụng cho tình huống của mình.
Không thực sự; đây là cách phức tạp cho mọi người khi sử dụng thành phần của tôi. Tất cả việc cần làm là tham khảo thành phần và mã sử dụng như: // Khởi tạo MyComponent bằng IP, cổng, v.v. MyComponent.SendString ("Điều này thật tuyệt"); MyComponent tăng sự kiện; cho dù chúng được xử lý bởi một dự án GUI hay không GUI không quan trọng và tôi không muốn người dùng chịu trách nhiệm kiểm tra InvokeRequired. – ComponentBuilder