2016-04-20 13 views
1

Ich entwickle eine WPF-Anwendung in C# und kommuniziere mit einem seriellen Gerät. Momentan zeige ich im Hauptfenster meiner Anwendung einige Informationen an, die ich durch periodisches Lesen von Zeilen vom seriellen Gerät erhalte.Anwendungsbreite serielle Schnittstelle

Manchmal muss ich ständig Daten vom seriellen Gerät in einer Datei empfangen und speichern. Ich stoppe andere Methoden, die den seriellen Anschluss verwenden (wie derjenige, der regelmäßig Zeilen liest, um im Hauptfenster angezeigt zu werden), so dass der Aufzeichnungsprozess nicht gestört wird. Es kann mühsam sein, den Zugriff auf den seriellen Port über die Anwendung hinweg zu verwalten, und so ist "System.UnauthorizedAccessException" nicht ungewöhnlich.

In jeder Methode oder Fenster in der Anwendung, die das serielle Gerät verwendet, definiere ich eine neue serielle Schnittstelle, öffne sie, lese Zeilen und schließe sie dann und entsorge sie. Ich habe jedoch gelesen, dass es eine gute Methode ist, den seriellen Port zu öffnen, wenn die Anwendung gestartet wird, und ihn zu schließen, wenn die Anwendung geschlossen wird, und ich sehe, warum dies hilfreich ist, wohin ich mit dieser Anwendung komme. Ich habe jedoch einige Fragen:

  • Wo sollte ich das serielle Port-Objekt definieren?
  • Wenn ich das serielle Port-Objekt aus mehr als einem Fenster oder Methode aufrufen, erstelle ich mehr als eine Instanz des seriellen Port-Objekts? Können Sie mehr als eine Instanz eines seriellen Anschlussobjekts für nur einen physischen seriellen Anschluss haben?
  • Wenn ich SerialPort.ReadLine() von zwei verschiedenen Methoden (auf zwei verschiedenen Threads) aufgerufen hätte, würde eine Zeile zu einer Methode und dann die nächste Zeile zu der anderen Methode gehen und so wiederholen? Wie kann ich alle seriellen Daten an beide weitergeben?

Antwort

0

Sie sollten eine separate Klasse erstellen, um die SerialPort-Verbindung zu verwalten. Es sollte einen eigenen Thread haben, der von der seriellen Schnittstelle liest. Es kann dann die Informationen, die es liest, an die anderen Stellen in Ihrer Anwendung verteilen. Ein guter Weg, dies zu tun ist mit Rx. Machen Sie ein Singleton aus dieser Klasse und injizieren Sie es an anderer Stelle in der Anwendung, die es benötigt.

Mit Rx können Sie Nachrichten von der seriellen Schnittstelle so oft wie nötig abonnieren.

  1. Erstellen Sie eine Klasse über die serielle Schnittstelle zu verwalten:

    public class SerialPortManager 
    { 
        private SerialPort; 
        private string comPort; 
        Subject<string> messageBus = new Subject<string>(); 
        public IObservable<string> MessageBus => messageBus; 
        private CancellationTokenSource cts = new CancellationTokenSource(); 
    
        public SerialPortManager(string comPort) 
        { 
        this.comport = comport; 
        } 
    
        public void Start() 
        { 
         ThreadStart ts = new ThreadStart(SerialDeviceThread); 
         Thread t = new Thread(ts); 
         t.IsBackground = true; 
         t.Name = this.Name; 
         t.Start(); 
        } 
    
        private void SerialDeviceThread() 
        { 
         this.serialPort = new SerialPort(this.comPort, ...); 
         while (true) 
         { 
          string line = this.serialPort.ReadLine(); 
          this.messageBus.OnNext(line); 
         } 
        } 
    } 
    
  2. erstellen Singelton dieser Klasse irgendwo:

    public static Lazy<SerialPortManager> SerialPortManager = 
        new Lazy<SerialPortManager>(x => { 
         var sm = new SerialPortManager("COM2"); 
         sm.Start(); 
         return sm; 
        }); 
    

und anderswo

SerialPortManager.Value.MessageBus.Subscribe(...) 

[Dies ist immer noch stark vereinfacht, würde ich Logik um den seriellen Port haben, um Fehler zu fangen und den Port neu zu erstellen, wenn es getrennt wird. Ich würde auch einen Dependency-Injektionscontainer (z. B. Autofac) anstelle eines statischen Werts verwenden.]

+0

könnten Sie bitte näher auf das Erstellen einer separaten Klasse für die serielle Schnittstelle und wie ich ein Singleton aus dieser Klasse und injizieren Sie es, wo immer in der Anwendung benötigt. Oder wenn Sie irgendwelche Links zu relevanten Dokumenten über das, was ich gerade erwähnt habe, oder über Rx haben. Wie wird der erste von Ihnen bereitgestellte Code verwendet? – thoward

+0

@thoward Ausarbeitung hinzugefügt. –

+0

Danke @IanMercer. Wie wäre es mit dem Abrufen der Zeichenfolge, nachdem ich die Subskriptionsanweisung habe? Ich bemühe mich, ein solches Beispiel zu finden, um mir einen Hinweis zu geben. Auch muss ich es eine "heiße" Observable wie in [diesem Link] (https://msdn.microsoft.com/en-us/library/hh242977 (v = vs.103) .aspx) machen, so dass Abonnenten auf verschiedene Threads erhalten die gleiche Zeichenfolge zur gleichen Zeit? – thoward

0

Es klingt wie, was Sie benötigen, ist ein Objekt, das den Zugriff auf Ihre serielle Schnittstelle verwaltet. Dieses Objekt würde das Port-Objekt einmal einrichten und einen neuen Thread starten, der fortlaufend Zeilen von der seriellen Schnittstelle lesen würde, und ein Ereignis auslösen, wenn es die Zeile gelesen hat. Dann würden Ihre anderen Anwendungsobjekte Delegaten an dieses Ereignis anfügen, wenn sie über Daten benachrichtigt werden möchten, die von der seriellen Schnittstelle kommen.Auf diese Weise würden Daten von der seriellen Schnittstelle immer an diejenigen gesendet, die daran interessiert waren. Abhängig von Ihrer Benutzeroberfläche müssen Sie die Invoke() - Methode auf Dispatcher (für WPF) oder auf einem Windows-Formularobjekt (für Windows-Formulare) verwenden, um sicherzustellen, dass das Ereignis über den UI-Thread ausgelöst wird, damit UI-Methoden korrekt aufgerufen werden können .

Verwandte Themen