簡體   English   中英

與僅同步的網絡設備對話的.NET CF 3.5表單

[英].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。 異步編程的概念非常清楚,只是不知道如何在這種情況下應用它們。

所以..任何輸入表示贊賞,還建議書等等。

聽起來,某種方式,某種程度上太像我當前正在研究的項目。 我擁有一次只能發送一個命令的硬件。 這些命令可能會超時,或者可能只是等到接收器喚醒為止。 命令以答復或未經請求的數據消息的形式出現。

我要做的實際上是用我現在要組成的一些名稱創建幾層

最低層-通信總線:

  • 知道如何發送和接收。
  • 知道如何將傳入的數據解析為“幀”,但僅此而已(它知道定界符和校驗和)。 這實際上是在OpenNETCF.IO串行庫中的緩沖線程中完成的。
  • 將已解析的幀放入隊列中以最小化接收器線程繁忙狀態
  • 有一個工作線程監視Rx隊列並調度幀
  • 公開一個簡單的“發送”界面(發送在上一層中進行處理)

下一層-API(?)層

設備監控器

  • 知道存在哪些終端設備
  • 知道我最后一次聽到他們的消息
  • 從通信總線接收幀並將其放入隊列(以免阻塞接收器)
  • 知道如何更好地解析幀
  • 引發特定於消息的事件
  • 節點聯機時發送消息(從消息處理程序中檢索)
  • 有兩個工作線程:
    • TxThread通過從que消息處理程序中提取來處理“一個和唯一一條傳出消息”問題
    • RxThread接收監視傳入的幀隊列,解析並調度這些消息

訊息管理員

  • 知道哪些消息需要發送到哪些設備
  • 知道每個消息的狀態(未發送,等待響應,超時等)
  • 允許過濾“發送”,“超時”等項目

服務層

  • 消耗並抽象API層
  • 向應用程序公開對象和事件(直接或通過REST)
  • 是否進行數據匯總(平均值,電池監控等)
  • 包含業務規則/邏輯

這里的要點是,盡管該庫中的幾乎所有內容在行為上都是異步的,但我沒有明確實現任何異步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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM