StephaneLenclud@123: // StephaneLenclud@123: // Copyright (C) 2014-2015 Stéphane Lenclud. StephaneLenclud@123: // StephaneLenclud@123: // This file is part of SharpDisplayManager. StephaneLenclud@123: // StephaneLenclud@123: // SharpDisplayManager is free software: you can redistribute it and/or modify StephaneLenclud@123: // it under the terms of the GNU General Public License as published by StephaneLenclud@123: // the Free Software Foundation, either version 3 of the License, or StephaneLenclud@123: // (at your option) any later version. StephaneLenclud@123: // StephaneLenclud@123: // SharpDisplayManager is distributed in the hope that it will be useful, StephaneLenclud@123: // but WITHOUT ANY WARRANTY; without even the implied warranty of StephaneLenclud@123: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the StephaneLenclud@123: // GNU General Public License for more details. StephaneLenclud@123: // StephaneLenclud@123: // You should have received a copy of the GNU General Public License StephaneLenclud@123: // along with SharpDisplayManager. If not, see . StephaneLenclud@123: // StephaneLenclud@123: StephaneLenclud@123: using System; sl@20: using System.Collections.Generic; sl@20: using System.Linq; sl@20: using System.Text; sl@20: using System.Threading.Tasks; sl@20: using System.Windows.Forms; sl@55: using SharpDisplay; sl@20: using System.ServiceModel; sl@20: using System.ServiceModel.Channels; sl@20: sl@20: sl@20: namespace SharpDisplayClient sl@20: { sl@25: /// sl@25: /// sl@25: /// sl@31: [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)] sl@55: public class Callback : ICallback, IDisposable sl@20: { sl@31: private MainForm MainForm { get; set; } sl@31: sl@31: public Callback(MainForm aMainForm) sl@31: { sl@31: MainForm = aMainForm; sl@31: } sl@31: sl@20: public void OnConnected() sl@20: { sl@20: //Debug.Assert(Thread.CurrentThread.IsThreadPoolThread); sl@20: //Trace.WriteLine("Callback thread = " + Thread.CurrentThread.ManagedThreadId); sl@20: sl@20: MessageBox.Show("OnConnected()", "Client"); sl@20: } sl@20: sl@20: sl@32: public void OnCloseOrder() sl@20: { sl@20: //Debug.Assert(Thread.CurrentThread.IsThreadPoolThread); sl@20: //Trace.WriteLine("Callback thread = " + Thread.CurrentThread.ManagedThreadId); sl@20: sl@21: //MessageBox.Show("OnServerClosing()", "Client"); sl@31: MainForm.CloseConnectionThreadSafe(); sl@31: MainForm.CloseThreadSafe(); sl@20: } sl@25: sl@25: //From IDisposable sl@25: public void Dispose() sl@25: { sl@25: sl@25: } sl@20: } sl@20: sl@20: sl@25: /// sl@25: /// sl@25: /// sl@31: [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)] sl@55: public class Client : DuplexClientBase sl@20: { sl@30: public string SessionId { get { return InnerChannel.SessionId; } } sl@26: sl@57: public Client(ICallback aCallback) sl@57: : base(new InstanceContext(aCallback), new NetTcpBinding(SecurityMode.None, true), new EndpointAddress("net.tcp://localhost:8001/DisplayService")) sl@20: { } sl@20: sl@32: public void SetName(string aClientName) sl@20: { sl@32: Channel.SetName(aClientName); sl@26: } sl@26: sl@62: public void SetLayout(TableLayout aLayout) sl@62: { sl@62: Channel.SetLayout(aLayout); sl@62: } sl@62: sl@74: public void SetField(DataField aField) sl@20: { sl@74: Channel.SetField(aField); sl@20: } sl@20: sl@74: public void SetFields(System.Collections.Generic.IList aFields) sl@20: { sl@74: Channel.SetFields(aFields); sl@67: } sl@67: sl@32: public int ClientCount() sl@32: { sl@32: return Channel.ClientCount(); sl@32: } sl@57: sl@57: public bool IsReady() sl@57: { sl@74: return State == CommunicationState.Opened || State == CommunicationState.Created; sl@57: } sl@20: } sl@73: sl@73: sl@73: /// sl@78: /// Handle connection with our Sharp Display Server. sl@78: /// If the connection is faulted it will attempt to restart it. sl@73: /// sl@73: public class DisplayClient sl@73: { sl@78: private Client iClient; sl@78: private Callback iCallback; sl@78: private bool resetingConnection = false; sl@78: sl@73: private MainForm MainForm { get; set; } sl@73: public string SessionId { get { return iClient.SessionId; } } sl@74: public string Name { get; private set; } sl@74: private TableLayout Layout { get; set; } sl@74: private System.Collections.Generic.IList Fields { get; set; } sl@74: sl@73: sl@73: public DisplayClient(MainForm aMainForm) sl@73: { sl@73: MainForm = aMainForm; sl@73: Name = ""; sl@74: Fields = new DataField[]{}; sl@73: } sl@73: sl@78: /// sl@78: /// Initialize our server connection. sl@78: /// sl@73: public void Open() sl@73: { sl@73: iCallback = new Callback(MainForm); sl@73: iClient = new Client(iCallback); sl@73: } sl@73: sl@78: /// sl@78: /// Terminate our server connection. sl@78: /// sl@73: public void Close() sl@73: { sl@73: iClient.Close(); sl@73: iClient = null; sl@73: iCallback.Dispose(); sl@73: iCallback = null; sl@73: } sl@73: sl@78: /// sl@78: /// Tells whether a server connection is available. sl@78: /// sl@78: /// True if a server connection is available. False otherwise. sl@73: public bool IsReady() sl@73: { sl@73: return (iClient != null && iCallback != null && iClient.IsReady()); sl@73: } sl@73: sl@78: /// sl@78: /// Check if our server connection is available and attempt reset it if it isn't. sl@78: /// This is notably dealing with timed out connections. sl@78: /// sl@73: public void CheckConnection() sl@73: { sl@78: if (!IsReady() && !resetingConnection) sl@73: { sl@74: //Try to reconnect sl@73: Open(); sl@74: sl@78: //Avoid stack overflow in case of persisting failure sl@78: resetingConnection = true; sl@78: sl@78: try sl@74: { sl@78: //On reconnect there is a bunch of properties we need to reset sl@78: if (Name != "") sl@78: { sl@78: iClient.SetName(Name); sl@78: } sl@78: sl@78: SetLayout(Layout); sl@80: iClient.SetFields(Fields); sl@74: } sl@78: finally sl@78: { sl@78: //Make sure our this state does not get out of sync sl@78: resetingConnection = true; sl@78: } sl@73: } sl@73: } sl@73: sl@73: public void SetName(string aClientName) sl@73: { sl@73: Name = aClientName; sl@73: CheckConnection(); sl@73: iClient.SetName(aClientName); sl@73: } sl@73: sl@73: sl@73: public void SetLayout(TableLayout aLayout) sl@73: { sl@74: Layout = aLayout; sl@73: CheckConnection(); sl@73: iClient.SetLayout(aLayout); sl@73: } sl@73: sl@80: /// sl@80: /// Set the specified field. sl@80: /// sl@80: /// sl@80: /// True if the specified field was set client side. False means you need to redefine all your fields using CreateFields. sl@80: public bool SetField(DataField aField) sl@73: { sl@74: int i = 0; sl@80: bool fieldFound = false; sl@74: foreach (DataField field in Fields) sl@74: { sl@74: if (field.Index == aField.Index) sl@74: { sl@74: //Update our field then sl@74: Fields[i] = aField; sl@80: fieldFound = true; sl@74: break; sl@74: } sl@74: i++; sl@74: } sl@74: sl@80: if (!fieldFound) sl@80: { sl@80: //Field not found, make to use SetFields with all your fields at least once after setting your layout. sl@80: return false; sl@80: } sl@80: sl@73: CheckConnection(); sl@74: iClient.SetField(aField); sl@80: return true; sl@73: } sl@73: sl@80: /// sl@80: /// Use this function when updating existing fields. sl@80: /// sl@80: /// sl@80: public bool SetFields(System.Collections.Generic.IList aFields) sl@80: { sl@80: int fieldFoundCount = 0; sl@80: foreach (DataField fieldUpdate in aFields) sl@80: { sl@80: int i = 0; sl@80: foreach (DataField existingField in Fields) sl@80: { sl@80: if (existingField.Index == fieldUpdate.Index) sl@80: { sl@80: //Update our field then sl@80: Fields[i] = fieldUpdate; sl@80: fieldFoundCount++; sl@80: //Move on to the next field sl@80: break; sl@80: } sl@80: i++; sl@80: } sl@80: } sl@80: sl@80: // sl@80: if (fieldFoundCount!=aFields.Count) sl@80: { sl@80: //Field not found, make sure to use SetFields with all your fields at least once after setting your layout. sl@80: return false; sl@80: } sl@80: sl@80: CheckConnection(); sl@80: iClient.SetFields(aFields); sl@80: return true; sl@80: } sl@80: sl@80: /// sl@80: /// Use this function when creating your fields. sl@80: /// sl@80: /// sl@80: public void CreateFields(System.Collections.Generic.IList aFields) sl@73: { sl@74: Fields = aFields; sl@73: CheckConnection(); sl@74: iClient.SetFields(aFields); sl@73: } sl@73: sl@73: public int ClientCount() sl@73: { sl@73: CheckConnection(); sl@73: return iClient.ClientCount(); sl@73: } sl@73: sl@73: sl@73: sl@73: } sl@73: sl@73: sl@20: }