= Chat Server and WPF Client = Download the code on [[https://github.com/scotpatti/chatdemo|github]] or an older version from here: [[attachment:ChatServer2013.zip]] == Chat Client == For the client code I used WPF and the MVVM pattern. From the bottom up the first thing I used is a DelegateCommand for the ICommands needed for buttons and what not. This makes the use of ICommand almost easy. {{{#!csharp using System; using System.Windows.Input; namespace ChatClient { class DelegateCommand : ICommand { private readonly Predicate<object> _canExecute; private readonly Action<object> _execute; public event EventHandler CanExecuteChanged; public DelegateCommand(Action<object> execute, Predicate<object> canExecute) { _execute = execute; _canExecute = canExecute; } public bool CanExecute(object parameter) { return _canExecute == null || _canExecute(parameter); } public void Execute(object parameter) { _execute(parameter); } public void RaiseCanExecuteChanged() { if (CanExecuteChanged != null) { CanExecuteChanged(this, EventArgs.Empty); } } } } }}} You can see this in the ViewModel used below: {{{#!csharp using System.ComponentModel; using ChatClient.Models; namespace ChatClient.ViewModels { /// <summary> /// Adaptive code only. You should only see things here that adapt /// the Model to the view. This is an abstraction of the Model for /// the express use by the View. /// </summary> class ClientViewModel : INotifyPropertyChanged { #region Properties //Elements bound to by the view public string Message { get { return _clientModel.CurrentMessage; } set { _clientModel.CurrentMessage = value; NotifyPropertyChanged("Message"); } } public string MessageBoard { get { return _clientModel.MessageBoard; } set { _clientModel.MessageBoard = value; NotifyPropertyChanged("MessageBoard"); } } public DelegateCommand ConnectCommand { get; set; } public DelegateCommand SendCommand { get; set; } #endregion #region Private and Internal Vars/Props private readonly ClientModel _clientModel; #endregion /// <summary> /// Constructor creates the Model! /// </summary> public ClientViewModel() { //Create ourselves a model _clientModel = new ClientModel(); //Subscribe to the Model's PropertyChanged event _clientModel.PropertyChanged += ClientModelChanged; //Create our two Command objects ConnectCommand = new DelegateCommand( a => _clientModel.Connect(), b => !_clientModel.Connected ); SendCommand = new DelegateCommand( a => _clientModel.Send(), b => _clientModel.Connected ); } #region Event Listeners private void ClientModelChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName.Equals("Connected")) { NotifyPropertyChanged("Connected"); ConnectCommand.RaiseCanExecuteChanged(); SendCommand.RaiseCanExecuteChanged(); } else if (e.PropertyName.Equals("MessageBoard")) { NotifyPropertyChanged("MessageBoard"); } } #endregion #region NPC Implementation public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged(string prop) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(prop)); } } #endregion NPC Implementation } } }}} The ViewModel above creates the Model in the constructor. The Model is shown below. {{{#!csharp using System.ComponentModel; using System.Net.Sockets; using System.Text; using System.Threading; namespace ChatClient.Models { class ClientModel : INotifyPropertyChanged { private TcpClient _socket; private NetworkStream _stream; private string _messageBoard; public string MessageBoard { get { return _messageBoard; } set { _messageBoard = value; NotifyPropertyChanged("MessageBoard"); } } private string _currentMessage; public string CurrentMessage { get {return _currentMessage;} set { _currentMessage = value; NotifyPropertyChanged("CurrentMessage"); } } private bool _connected; public ClientModel() { _connected = false; } public bool Connected { get {return _connected; } set { _connected = value; NotifyPropertyChanged("Connected"); } } public void Connect() { _socket = new TcpClient(); _socket.Connect("127.0.0.1", 8888); _stream = _socket.GetStream(); Connected = true; Send(); _messageBoard = "Welcome: " + _currentMessage; var thread = new Thread(GetMessage); thread.Start(); } public void Send() { WriteString(_currentMessage + "$"); } private void GetMessage() { while (true) { string msg = ReadString(); MessageBoard += "\r\n" + msg; } } private string ReadString() { var bytes = new byte[16384]; _stream.Read(bytes, 0, _socket.ReceiveBufferSize); string msg = Encoding.ASCII.GetString(bytes); int index = msg.IndexOf("$") > 0 ? msg.IndexOf("$") : msg.IndexOf('\0'); return msg.Substring(0, index); } private void WriteString(string msg) { byte[] bytes = Encoding.ASCII.GetBytes(msg); _stream.Write(bytes, 0, bytes.Length); _stream.Flush(); } #region NPC public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged(string prop) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(prop)); } } #endregion } } }}} Finally the XAML View for this project was very simple and is bound (e.g. it creates its controller) to the ViewModel which is started from App.xaml in the {{{StartupUri="MainWindow.xaml"}}} ). Here is the view: {{{ <Window x:Class="ChatClient.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:my="clr-namespace:ChatClient.ViewModels" Title="Chat Client" Height="392" Width="561"> <Window.DataContext> <my:ClientViewModel /> </Window.DataContext> <Grid> <Grid.RowDefinitions> <RowDefinition /> </Grid.RowDefinitions> <Label Content="Message:" HorizontalAlignment="Left" Margin="10,0,0,57" Width="58" Height="26" VerticalAlignment="Bottom"/> <TextBox Height="70" Margin="73,0,10,8" TextWrapping="Wrap" Text="{Binding Message}" VerticalAlignment="Bottom"/> <TextBox Margin="10,10,10,83" TextWrapping="Wrap" Text="{Binding MessageBoard}" ScrollViewer.CanContentScroll="True" VerticalScrollBarVisibility="Auto"/> <Button Content="Send" Command="{Binding SendCommand}" HorizontalAlignment="Left" Margin="10,0,0,35" VerticalAlignment="Bottom" Width="58" Height="22"/> <Button Content="Connect" Command="{Binding ConnectCommand}" HorizontalAlignment="Left" Margin="10,0,0,8" VerticalAlignment="Bottom" Width="58"/> </Grid> </Window> }}} == Chat Server == The server is in two files. The first is program.cs {{{#!csharp using System; using System.Collections; using System.Net; using System.Net.Sockets; using System.Text; namespace ChatServer { class Program { public static Hashtable ClientList = new Hashtable(); static void Main() { var serverSocket = new TcpListener(IPAddress.Any, 8888); serverSocket.Start(); Console.WriteLine("Chat server started..."); while (true) { //This next line of code actually blocks TcpClient clientSocket = serverSocket.AcceptTcpClient(); //Somebody connected and set us data string dataFromClient = GetStringFromStream(clientSocket); ClientList.Add(dataFromClient, clientSocket); Broadcast(dataFromClient + " joined.", dataFromClient, false); Console.WriteLine(dataFromClient + " joined cat room."); var client = new HandleClient(); client.StartClient(clientSocket, dataFromClient); } } public static void Broadcast(string msg, string uname, bool flag) { foreach (DictionaryEntry item in ClientList) { var broadcastSocket = (TcpClient)item.Value; NetworkStream broadcastStream = broadcastSocket.GetStream(); byte[] broadcastBytes = flag ? Encoding.ASCII.GetBytes(uname + " says: " + msg) : Encoding.ASCII.GetBytes(msg); broadcastStream.Write(broadcastBytes, 0, broadcastBytes.Length); broadcastStream.Flush(); } } public static string GetStringFromStream(TcpClient clientSocket) { var bytesFrom = new byte[16384]; NetworkStream networkStream = clientSocket.GetStream(); networkStream.Read(bytesFrom, 0, clientSocket.ReceiveBufferSize); string dataFromClient = Encoding.ASCII.GetString(bytesFrom); return dataFromClient.Substring(0, dataFromClient.IndexOf("$", StringComparison.Ordinal)); } } } }}} The second file is the part handling each client. {{{#!csharp using System; using System.Net.Sockets; using System.Threading; namespace ChatServer { public class HandleClient { private TcpClient _clientSocket; private string _clientNumber; public void StartClient(TcpClient clientSocket, string clientNumber) { _clientNumber = clientNumber; _clientSocket = clientSocket; var thread = new Thread(DoChat); thread.Start(); } private void DoChat() { var bytesFrom = new byte[16384]; int requestCount = 0; while (true) { try { requestCount += 1; string dataFromClient = Program.GetStringFromStream(_clientSocket); Console.WriteLine("From Client - " + _clientNumber + ": " + dataFromClient); Program.Broadcast(dataFromClient, _clientNumber, true); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } } } } } }}}