[英].NET CF 3.5 Forms talking to sync-only network device
好的,我該在這里問我的第一個問題了...
我創建了許多視圖(使用OpenNETCF.IoC和resco控件的CF 3.5用戶控件)和一個導航控制器。
我還為一個非常好奇的專有網絡設備創建了一個抽象層(“驅動程序”)。 命令只能在設備上同步執行,但是我使用讀取器線程來偵聽來自設備的消息(可能隨時出現,或者響應於同步命令)。 這些消息可以在事件中分派或排隊。
在“驅動程序”界面中類似這樣:
public Response ExecuteCommand(Command command);
<=這是同步呼叫。 某些命令可能會運行幾分鍾。
public event DeviceMessageReceivedEvent;
<=如果已訂閱,則不是直接應答對上述方法的調用的傳入消息將在事件args中調度。 這將從閱讀器線程中調用。
public Queue DeviceMessages;
<=如果該事件未訂閱,則此類消息將發送至此處。
還有一個方便的應用程序外觀,但它基本上只是ExecuteCommand調用的精美包裝,因此在此將其省略。
問題:
我如何最好地將在事件和/或隊列中接收的數據連接到視圖,以及如何最好地通過ExecuteCommand方法實現異步包裝-重申一下,由於設備網絡的限制,該方法必須同步運行協議(是的,這確實很糟糕。)
在使用.NET CF 3.5 WinForms進行了異步編程的大量閱讀后,我無所適從。 在第一個演示中,我經常使用DataBindings,但這導致了一些問題,因為在需要時沒有明顯的方法可以使用Control.Invoke。 我還通過與UI線程同步執行所有命令,並使用匿名線程而不是事件來輪詢隊列中的消息,從而解決了異步執行問題。 由於明顯的原因,我非常想更改此設置。
CF不提供BeginInvoke和EndInvoke,但我想這些將足夠簡單以重新實現?
我應該創建一個以視圖為中心的靜態模型嗎? 那會簡化事情嗎?
我是否應該創建一個額外的“中間”線程來處理模型/視圖與驅動程序之間的狀態轉移? 那會簡化事情嗎?
...?
我想我正在這里就常規設計原則進行一些集思廣益。 我從來都不是一個UI使用者,主要是從事系統編程,而且從來沒有比我可以避免的更多的.NET。 異步編程的概念非常清楚,只是不知道如何在這種情況下應用它們。
所以..任何輸入表示贊賞,還建議書等等。
聽起來,某種方式,某種程度上太像我當前正在研究的項目。 我擁有一次只能發送一個命令的硬件。 這些命令可能會超時,或者可能只是等到接收器喚醒為止。 命令以答復或未經請求的數據消息的形式出現。
我要做的實際上是用我現在要組成的一些名稱創建幾層
最低層-通信總線:
下一層-API(?)層
設備監控器
訊息管理員
服務層
這里的要點是,盡管該庫中的幾乎所有內容在行為上都是異步的,但我沒有明確實現任何異步API。 UI只是查找傳入內容的事件(INotifyPropertyChanged大量出現)。 對於傳出,它會執行“阻止將引腳1設置為高電平的請求”之類的操作。 服務層進行一些檢查以驗證實際在遠程端上發生的操作,但是UI只是查看“引腳狀態”屬性,並且當它實際變為高電平(在服務層中已驗證)時,它將進行更新。
我最終以大量特定的IAsyncResult Begin / End調用以及其他有趣的東西而告終,從而導致該解決方案並不是非常適合或非常不適合單核單管道CPU。 但是從那時起,我在一個新項目中再次探討了這個問題。 在這里,我創建了一個簡單的包裝程序,使我可以輕松觸發並忘記CF中的異步調用。 它可能並不完美,但是在我需要做的事情上做得很好。
請注意,這僅適用於UI內容。
現在,新體系結構包括通用連接層(通過公共接口的串行和tcp),特定於設備的API層(在該級別上具有很少共同點的幾個設備),特定於設備的表示控制器,通用表示模型(tuns)在視圖中,它們實際上有很多共同點),最重要的是,視圖由表示控制器通過表示模型間接控制。 對於所有設備,視圖並非完全相同(特定於設備的功能),但是演示控制器控制視圖中可見/加載的內容。
但事不宜遲,
調用示例:
AsyncCallback callback = delegate(IAsyncResult result)
{
IView2MainContainer.StopWaiting();
try
{
AsyncHelper.EndInvoke(result);
}
catch (Exception ex)
{
RescoMessageBoxHelper.ShowOK(
string.Format(StringResources.Message_FirmwareUpdateError,
ex.Message), MessageBoxIcon.Hand);
return;
}
RescoMessageBoxHelper.ShowOK(StringResources.Message_FirmwareUpdateComplete, MessageBoxIcon.Asterisk);
};
AsyncHelper.BeginInvoke(
callback,
delegate
{
IView2MainContainer.StartWaiting(StringResources.Message_WaitFirmwareUpdate);
presenterModel.CurrentDevice.UpdatePrinterFirmware(firmwareDataBuffer);
}
);
實現:
using System;
using System.Collections.Generic;
using System.Threading;
namespace Allen.IView2.Common
{
public static class AsyncHelper
{
private static readonly object resultsLock = new object();
private static volatile List<AsyncResultImpl> results = new List<AsyncResultImpl>();
public static void EndInvoke(IAsyncResult result)
{
if (!(result is AsyncResultImpl))
throw new InvalidOperationException("The async result was of an unknown type.");
lock (resultsLock)
{
if (!results.Contains((AsyncResultImpl) result))
{
throw new InvalidOperationException("The async result was unknown");
}
results.Remove((AsyncResultImpl) result);
}
((AsyncResultImpl) result).AsyncWaitHandle.WaitOne();
Exception ex = ((AsyncResultImpl) result).Exception;
((AsyncResultImpl) result).Dispose();
if (ex != null)
{
throw ex;
}
}
public static void BeginInvoke(AsyncCallback callback, Action action)
{
var result = new AsyncResultImpl(callback, null);
lock (resultsLock)
{
results.Add(result);
}
ThreadPool.QueueUserWorkItem(delegate
{
try
{
action.Invoke();
}
catch (Exception ex)
{
result.Complete(ex);
return;
}
result.Complete();
});
}
}
}
using System;
using System.Threading;
namespace Allen.IView2.Common
{
public class AsyncResultImpl : IAsyncResult, IDisposable
{
private AsyncCallback callback;
private Exception exception;
private object state;
private ManualResetEvent waitHandle;
public AsyncResultImpl(AsyncCallback callback, object state)
{
this.callback = callback;
this.state = state;
waitHandle = new ManualResetEvent(false);
}
public ManualResetEvent AsyncWaitHandle
{
get { return waitHandle; }
}
public Exception Exception
{
get { return exception; }
}
public object AsyncState
{
get { return state; }
}
WaitHandle IAsyncResult.AsyncWaitHandle
{
get { return AsyncWaitHandle; }
}
public bool CompletedSynchronously
{
get { return false; }
}
public bool IsCompleted
{
get { return waitHandle.WaitOne(0, false); }
}
public void Dispose() // lazy dispose
{
if (null != waitHandle)
{
waitHandle.Close();
waitHandle = null;
state = null;
callback = null;
}
}
public void Complete()
{
Complete(null);
}
public void Complete(Exception exception)
{
this.exception = exception;
waitHandle.Set();
if (null != callback)
if (callback.GetInvocationList().Length > 1)
throw new InvalidOperationException("A callback must not be multicast.");
if (null != callback)
{
try
{
callback(this);
}
catch
{
// nom nom
}
}
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.