Client/Client.cs
author StephaneLenclud
Wed, 18 Mar 2015 21:47:06 +0100
changeset 129 9d5867ce966a
parent 80 408ef0501cb7
child 138 426cc984fd18
permissions -rw-r--r--
Looks like we have a solution for our bring to foreground problem.
StephaneLenclud@123
     1
//
StephaneLenclud@123
     2
// Copyright (C) 2014-2015 Stéphane Lenclud.
StephaneLenclud@123
     3
//
StephaneLenclud@123
     4
// This file is part of SharpDisplayManager.
StephaneLenclud@123
     5
//
StephaneLenclud@123
     6
// SharpDisplayManager is free software: you can redistribute it and/or modify
StephaneLenclud@123
     7
// it under the terms of the GNU General Public License as published by
StephaneLenclud@123
     8
// the Free Software Foundation, either version 3 of the License, or
StephaneLenclud@123
     9
// (at your option) any later version.
StephaneLenclud@123
    10
//
StephaneLenclud@123
    11
// SharpDisplayManager is distributed in the hope that it will be useful,
StephaneLenclud@123
    12
// but WITHOUT ANY WARRANTY; without even the implied warranty of
StephaneLenclud@123
    13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
StephaneLenclud@123
    14
// GNU General Public License for more details.
StephaneLenclud@123
    15
//
StephaneLenclud@123
    16
// You should have received a copy of the GNU General Public License
StephaneLenclud@123
    17
// along with SharpDisplayManager.  If not, see <http://www.gnu.org/licenses/>.
StephaneLenclud@123
    18
//
StephaneLenclud@123
    19
StephaneLenclud@123
    20
using System;
sl@20
    21
using System.Collections.Generic;
sl@20
    22
using System.Linq;
sl@20
    23
using System.Text;
sl@20
    24
using System.Threading.Tasks;
sl@20
    25
using System.Windows.Forms;
sl@55
    26
using SharpDisplay;
sl@20
    27
using System.ServiceModel;
sl@20
    28
using System.ServiceModel.Channels;
sl@20
    29
sl@20
    30
sl@20
    31
namespace SharpDisplayClient
sl@20
    32
{
sl@25
    33
    /// <summary>
sl@25
    34
    ///
sl@25
    35
    /// </summary>
sl@31
    36
    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
sl@55
    37
    public class Callback : ICallback, IDisposable
sl@20
    38
    {
sl@31
    39
        private MainForm MainForm { get; set; }
sl@31
    40
sl@31
    41
        public Callback(MainForm aMainForm)
sl@31
    42
        {
sl@31
    43
            MainForm = aMainForm;
sl@31
    44
        }
sl@31
    45
sl@20
    46
        public void OnConnected()
sl@20
    47
        {
sl@20
    48
            //Debug.Assert(Thread.CurrentThread.IsThreadPoolThread);
sl@20
    49
            //Trace.WriteLine("Callback thread = " + Thread.CurrentThread.ManagedThreadId);
sl@20
    50
sl@20
    51
            MessageBox.Show("OnConnected()", "Client");
sl@20
    52
        }
sl@20
    53
sl@20
    54
sl@32
    55
        public void OnCloseOrder()
sl@20
    56
        {
sl@20
    57
            //Debug.Assert(Thread.CurrentThread.IsThreadPoolThread);
sl@20
    58
            //Trace.WriteLine("Callback thread = " + Thread.CurrentThread.ManagedThreadId);
sl@20
    59
sl@21
    60
            //MessageBox.Show("OnServerClosing()", "Client");
sl@31
    61
            MainForm.CloseConnectionThreadSafe();
sl@31
    62
            MainForm.CloseThreadSafe();
sl@20
    63
        }
sl@25
    64
sl@25
    65
        //From IDisposable
sl@25
    66
        public void Dispose()
sl@25
    67
        {
sl@25
    68
sl@25
    69
        }
sl@20
    70
    }
sl@20
    71
sl@20
    72
sl@25
    73
    /// <summary>
sl@25
    74
    ///
sl@25
    75
    /// </summary>
sl@31
    76
    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
sl@55
    77
    public class Client : DuplexClientBase<IService>
sl@20
    78
    {
sl@30
    79
        public string SessionId { get { return InnerChannel.SessionId; } }
sl@26
    80
sl@57
    81
        public Client(ICallback aCallback)
sl@57
    82
            : base(new InstanceContext(aCallback), new NetTcpBinding(SecurityMode.None, true), new EndpointAddress("net.tcp://localhost:8001/DisplayService"))
sl@20
    83
        { }
sl@20
    84
sl@32
    85
        public void SetName(string aClientName)
sl@20
    86
        {
sl@32
    87
            Channel.SetName(aClientName);
sl@26
    88
        }
sl@26
    89
sl@62
    90
        public void SetLayout(TableLayout aLayout)
sl@62
    91
        {
sl@62
    92
            Channel.SetLayout(aLayout);
sl@62
    93
        }
sl@62
    94
sl@74
    95
        public void SetField(DataField aField)
sl@20
    96
        {
sl@74
    97
            Channel.SetField(aField);
sl@20
    98
        }
sl@20
    99
sl@74
   100
        public void SetFields(System.Collections.Generic.IList<DataField> aFields)
sl@20
   101
        {
sl@74
   102
            Channel.SetFields(aFields);
sl@67
   103
        }
sl@67
   104
sl@32
   105
        public int ClientCount()
sl@32
   106
        {
sl@32
   107
            return Channel.ClientCount();
sl@32
   108
        }
sl@57
   109
sl@57
   110
        public bool IsReady()
sl@57
   111
        {
sl@74
   112
            return State == CommunicationState.Opened || State == CommunicationState.Created;
sl@57
   113
        }
sl@20
   114
    }
sl@73
   115
sl@73
   116
sl@73
   117
    /// <summary>
sl@78
   118
    /// Handle connection with our Sharp Display Server.
sl@78
   119
    /// If the connection is faulted it will attempt to restart it.
sl@73
   120
    /// </summary>
sl@73
   121
    public class DisplayClient
sl@73
   122
    {
sl@78
   123
        private Client iClient;
sl@78
   124
        private Callback iCallback;
sl@78
   125
        private bool resetingConnection = false;
sl@78
   126
sl@73
   127
        private MainForm MainForm { get; set; }
sl@73
   128
        public string SessionId { get { return iClient.SessionId; } }
sl@74
   129
        public string Name { get; private set; }
sl@74
   130
        private TableLayout Layout { get; set; }
sl@74
   131
        private System.Collections.Generic.IList<DataField> Fields { get; set; }
sl@74
   132
sl@73
   133
sl@73
   134
        public DisplayClient(MainForm aMainForm)
sl@73
   135
        {
sl@73
   136
            MainForm = aMainForm;
sl@73
   137
            Name = "";
sl@74
   138
            Fields = new DataField[]{};
sl@73
   139
        }
sl@73
   140
sl@78
   141
        /// <summary>
sl@78
   142
        /// Initialize our server connection.
sl@78
   143
        /// </summary>
sl@73
   144
        public void Open()
sl@73
   145
        {
sl@73
   146
            iCallback = new Callback(MainForm);
sl@73
   147
            iClient = new Client(iCallback);
sl@73
   148
        }
sl@73
   149
sl@78
   150
        /// <summary>
sl@78
   151
        /// Terminate our server connection.
sl@78
   152
        /// </summary>
sl@73
   153
        public void Close()
sl@73
   154
        {
sl@73
   155
            iClient.Close();
sl@73
   156
            iClient = null;
sl@73
   157
            iCallback.Dispose();
sl@73
   158
            iCallback = null;
sl@73
   159
        }
sl@73
   160
sl@78
   161
        /// <summary>
sl@78
   162
        /// Tells whether a server connection is available.
sl@78
   163
        /// </summary>
sl@78
   164
        /// <returns>True if a server connection is available. False otherwise.</returns>
sl@73
   165
        public bool IsReady()
sl@73
   166
        {
sl@73
   167
            return (iClient != null && iCallback != null && iClient.IsReady());
sl@73
   168
        }
sl@73
   169
sl@78
   170
        /// <summary>
sl@78
   171
        /// Check if our server connection is available and attempt reset it if it isn't.
sl@78
   172
        /// This is notably dealing with timed out connections.
sl@78
   173
        /// </summary>
sl@73
   174
        public void CheckConnection()
sl@73
   175
        {
sl@78
   176
            if (!IsReady() && !resetingConnection)
sl@73
   177
            {
sl@74
   178
                //Try to reconnect
sl@73
   179
                Open();
sl@74
   180
sl@78
   181
                //Avoid stack overflow in case of persisting failure
sl@78
   182
                resetingConnection = true;
sl@78
   183
sl@78
   184
                try
sl@74
   185
                {
sl@78
   186
                    //On reconnect there is a bunch of properties we need to reset
sl@78
   187
                    if (Name != "")
sl@78
   188
                    {
sl@78
   189
                        iClient.SetName(Name);
sl@78
   190
                    }
sl@78
   191
sl@78
   192
                    SetLayout(Layout);
sl@80
   193
                    iClient.SetFields(Fields);
sl@74
   194
                }
sl@78
   195
                finally
sl@78
   196
                {
sl@78
   197
                    //Make sure our this state does not get out of sync
sl@78
   198
                    resetingConnection = true;
sl@78
   199
                }
sl@73
   200
            }
sl@73
   201
        }
sl@73
   202
sl@73
   203
        public void SetName(string aClientName)
sl@73
   204
        {
sl@73
   205
            Name = aClientName;
sl@73
   206
            CheckConnection();
sl@73
   207
            iClient.SetName(aClientName);
sl@73
   208
        }
sl@73
   209
sl@73
   210
sl@73
   211
        public void SetLayout(TableLayout aLayout)
sl@73
   212
        {
sl@74
   213
            Layout = aLayout;
sl@73
   214
            CheckConnection();
sl@73
   215
            iClient.SetLayout(aLayout);
sl@73
   216
        }
sl@73
   217
sl@80
   218
        /// <summary>
sl@80
   219
        /// Set the specified field.
sl@80
   220
        /// </summary>
sl@80
   221
        /// <param name="aField"></param>
sl@80
   222
        /// <returns>True if the specified field was set client side. False means you need to redefine all your fields using CreateFields.</returns>
sl@80
   223
        public bool SetField(DataField aField)
sl@73
   224
        {
sl@74
   225
            int i = 0;
sl@80
   226
            bool fieldFound = false;
sl@74
   227
            foreach (DataField field in Fields)
sl@74
   228
            {
sl@74
   229
                if (field.Index == aField.Index)
sl@74
   230
                {
sl@74
   231
                    //Update our field then
sl@74
   232
                    Fields[i] = aField;
sl@80
   233
                    fieldFound = true;
sl@74
   234
                    break;
sl@74
   235
                }
sl@74
   236
                i++;
sl@74
   237
            }
sl@74
   238
sl@80
   239
            if (!fieldFound)
sl@80
   240
            {
sl@80
   241
                //Field not found, make to use SetFields with all your fields at least once after setting your layout.
sl@80
   242
                return false;
sl@80
   243
            }
sl@80
   244
sl@73
   245
            CheckConnection();
sl@74
   246
            iClient.SetField(aField);
sl@80
   247
            return true;
sl@73
   248
        }
sl@73
   249
sl@80
   250
        /// <summary>
sl@80
   251
        /// Use this function when updating existing fields.
sl@80
   252
        /// </summary>
sl@80
   253
        /// <param name="aFields"></param>
sl@80
   254
        public bool SetFields(System.Collections.Generic.IList<DataField> aFields)
sl@80
   255
        {
sl@80
   256
            int fieldFoundCount = 0;
sl@80
   257
            foreach (DataField fieldUpdate in aFields)
sl@80
   258
            {
sl@80
   259
                int i = 0;
sl@80
   260
                foreach (DataField existingField in Fields)
sl@80
   261
                {
sl@80
   262
                    if (existingField.Index == fieldUpdate.Index)
sl@80
   263
                    {
sl@80
   264
                        //Update our field then
sl@80
   265
                        Fields[i] = fieldUpdate;
sl@80
   266
                        fieldFoundCount++;
sl@80
   267
                        //Move on to the next field
sl@80
   268
                        break;
sl@80
   269
                    }
sl@80
   270
                    i++;
sl@80
   271
                }
sl@80
   272
            }
sl@80
   273
sl@80
   274
            //
sl@80
   275
            if (fieldFoundCount!=aFields.Count)
sl@80
   276
            {
sl@80
   277
                //Field not found, make sure to use SetFields with all your fields at least once after setting your layout.
sl@80
   278
                return false;
sl@80
   279
            }
sl@80
   280
sl@80
   281
            CheckConnection();
sl@80
   282
            iClient.SetFields(aFields);
sl@80
   283
            return true;
sl@80
   284
        }
sl@80
   285
sl@80
   286
        /// <summary>
sl@80
   287
        /// Use this function when creating your fields.
sl@80
   288
        /// </summary>
sl@80
   289
        /// <param name="aFields"></param>
sl@80
   290
        public void CreateFields(System.Collections.Generic.IList<DataField> aFields)
sl@73
   291
        {
sl@74
   292
            Fields = aFields;
sl@73
   293
            CheckConnection();
sl@74
   294
            iClient.SetFields(aFields);
sl@73
   295
        }
sl@73
   296
sl@73
   297
        public int ClientCount()
sl@73
   298
        {
sl@73
   299
            CheckConnection();
sl@73
   300
            return iClient.ClientCount();
sl@73
   301
        }
sl@73
   302
sl@73
   303
sl@73
   304
sl@73
   305
    }
sl@73
   306
sl@73
   307
sl@20
   308
}