Click here to Skip to main content
16,022,536 members
Please Sign up or sign in to vote.
2.33/5 (3 votes)
I have created a application in WPF for LAN Chat. I have referenced this link:
http://www.geekpedia.com/tutorial239_Csharp-Chat-Part-1---Building-the-Chat-Client.html
and
http://www.geekpedia.com/tutorial239_Csharp-Chat-Part-2---Building-the-Chat-Client.html

The program compiles fine but I am facing some errors at runtime. Can any body help me? I am posting my WPF code here:

Server Chat:

XAML Code:

<pre lang="xml"><Window x:Class="chatclientwpf.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="597" Width="552">
    <Grid>
        <Label Height="27" Name="label1" VerticalAlignment="Top" HorizontalAlignment="Left" Width="60">Server IP:</Label>
        <TextBox Height="23" Margin="92,4,166,0" Name="txtIp" VerticalAlignment="Top">192.168.1.3</TextBox>
        <Label Height="28" HorizontalAlignment="Left" Margin="0,51,0,0" Name="label2" VerticalAlignment="Top" Width="70">User Name:</Label>
        <TextBox Height="23" Margin="92,51,166,0" Name="txtUser" VerticalAlignment="Top">Aditya</TextBox>
        <Button Height="23" HorizontalAlignment="Right" Margin="0,51.138,70,0" Name="btnConnect" VerticalAlignment="Top" Width="75" Click="btnConnect_Click">Connect</Button>
        <TextBox Margin="27,99,59,178" Name="txtLog" IsEnabled="False" VerticalScrollBarVisibility="Visible" />
        <TextBox Height="57" Margin="27,0,144,79" Name="txtMessage" VerticalAlignment="Bottom" VerticalScrollBarVisibility="Auto"/>
        <Button Height="36" HorizontalAlignment="Right" Margin="0,0,59,90" Name="btnSend" VerticalAlignment="Bottom" Width="75" Click="btnSend_Click">Send</Button>
    </Grid>
</Window>






C# coding:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.IO;

namespace ChatServerWPF
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }
        private delegate void UpdateStatusCallback(string strMessage);

        private void btnListenbutton_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                // Parse the server's IP address out of the TextBox
                IPAddress ipAddr = IPAddress.Parse(txtIp.Text);

                // Create a new instance of the ChatServer object
                ChatServer mainServer = new ChatServer(ipAddr);

                // Hook the StatusChanged event handler to mainServer_StatusChanged
                ChatServer.StatusChanged += new StatusChangedEventHandler(mainServer_StatusChanged);

                // Start listening for connections
                mainServer.StartListening();

                // Show that we started to listen for connections
                txtLog.AppendText("Monitoring for connections...\r\n");
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error: "+ex);
            }
        }
        public void mainServer_StatusChanged(object sender, StatusChangedEventArgs e)
        {
            // Call the method that updates the form
            this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new UpdateStatusCallback(this.UpdateStatus), new object[] { e.EventMessage });
        }



        private void UpdateStatus(string strMessage)
        {
            // Updates the log with the message
            txtLog.AppendText(strMessage + "\r\n");
        }



    }
}


ChatServer.cs file:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
using System.Collections;

namespace ChatServerWPF
{
    // Holds the arguments for the StatusChanged event
    
    public class StatusChangedEventArgs : EventArgs
    {
       
        // The argument we're interested in is a message describing the event
        private string EventMsg;
        // Property for retrieving and setting the event message
        public string EventMessage
        {
            get
            {
                return EventMsg;
            }
            set
            {
                EventMsg = value;
            }
        }

        // Constructor for setting the event message
        public StatusChangedEventArgs(string strEventMsg)
        {
            EventMsg = strEventMsg;
        }
    }

    // This delegate is needed to specify the parameters we're passing with our event
    public delegate void StatusChangedEventHandler(object sender, StatusChangedEventArgs e);
    
    class ChatServer
    {
        // This hash table stores users and connections (browsable by user)
        public static Hashtable htUsers = new Hashtable(30); // 30 users at one time limit

        // This hash table stores connections and users (browsable by connection)
        public static Hashtable htConnections = new Hashtable(30); // 30 users at one time limit

        // Will store the IP address passed to it
        private IPAddress ipAddress;
        private TcpClient tcpClient;

        // The event and its argument will notify the form when a user has connected, disconnected, send message, etc.
        public static event StatusChangedEventHandler StatusChanged;
        private static StatusChangedEventArgs e;
        
        // The constructor sets the IP address to the one retrieved by the instantiating object
        public ChatServer(IPAddress address)
        {
            ipAddress = address;
        }
        
        // The thread that will hold the connection listener
        private Thread thrListener;

        // The TCP object that listens for connections
        private TcpListener tlsClient;

        // Will tell the while loop to keep monitoring for connections
        bool ServRunning = false;

        // Add the user to the hash tables
        public static void AddUser(TcpClient tcpUser, string strUsername)
        {
            // First add the username and associated connection to both hash tables
            ChatServer.htUsers.Add(strUsername, tcpUser);
            ChatServer.htConnections.Add(tcpUser, strUsername);

            // Tell of the new connection to all other users and to the server form
            SendAdminMessage(htConnections[tcpUser] + " has joined us");
        }

        // Remove the user from the hash tables
        public static void RemoveUser(TcpClient tcpUser)
        {
            // If the user is there
            if (htConnections[tcpUser] != null)
            {
                // First show the information and tell the other users about the disconnection
                SendAdminMessage(htConnections[tcpUser] + " has left us");

                // Remove the user from the hash table
                ChatServer.htUsers.Remove(ChatServer.htConnections[tcpUser]);
                ChatServer.htConnections.Remove(tcpUser);
            }
        }

        // This is called when we want to raise the StatusChanged event
        public static void OnStatusChanged(StatusChangedEventArgs e)
        {
            StatusChangedEventHandler statusHandler = StatusChanged;
            if (statusHandler != null)
            {
                // Invoke the delegate
                statusHandler(null, e);
            }
        }



        // Send administrative messages
        public static void SendAdminMessage(string Message)
        {
            StreamWriter swSenderSender;

            // First of all, show in our application who says what
            e = new StatusChangedEventArgs("Administrator: " + Message);
            OnStatusChanged(e);

            // Create an array of TCP clients, the size of the number of users we have
            TcpClient[] tcpClients = new TcpClient[ChatServer.htUsers.Count];
            
            // Copy the TcpClient objects into the array
            ChatServer.htUsers.Values.CopyTo(tcpClients, 0);

            // Loop through the list of TCP clients
            for (int i = 0; i < tcpClients.Length; i++)
            {
                // Try sending a message to each
                try
                {
                    // If the message is blank or the connection is null, break out
                    if (Message.Trim() == "" || tcpClients[i] == null)
                    {
                        continue;
                    }

                    // Send the message to the current user in the loop
                    swSenderSender = new StreamWriter(tcpClients[i].GetStream());
                    swSenderSender.WriteLine("Administrator: " + Message);
                    swSenderSender.Flush();
                    swSenderSender = null;
                }

                catch // If there was a problem, the user is not there anymore, remove him
                {
                    RemoveUser(tcpClients[i]);
                }
            }
        }



        // Send messages from one user to all the others
        public static void SendMessage(string From, string Message)
        {
            StreamWriter swSenderSender;

            // First of all, show in our application who says what
            e = new StatusChangedEventArgs(From + " says: " + Message);
            OnStatusChanged(e);

            // Create an array of TCP clients, the size of the number of users we have
            TcpClient[] tcpClients = new TcpClient[ChatServer.htUsers.Count];

            // Copy the TcpClient objects into the array
            ChatServer.htUsers.Values.CopyTo(tcpClients, 0);

            // Loop through the list of TCP clients
            for (int i = 0; i < tcpClients.Length; i++)
            {
                // Try sending a message to each
                try
                {
                    // If the message is blank or the connection is null, break out
                    if (Message.Trim() == "" || tcpClients[i] == null)
                    {
                        continue;
                    }

                    // Send the message to the current user in the loop
                    swSenderSender = new StreamWriter(tcpClients[i].GetStream());
                    swSenderSender.WriteLine(From + " says: " + Message);
                    swSenderSender.Flush();
                    swSenderSender = null;
                }//try

                catch // If there was a problem, the user is not there anymore, remove him
                {
                    RemoveUser(tcpClients[i]);
                }
            }//forloop
        }//send message

        public void StartListening()
        {
            // Get the IP of the first network device, however this can prove unreliable on certain configurations
            IPAddress ipaLocal = ipAddress;

            // Create the TCP listener object using the IP of the server and the specified port
            tlsClient = new TcpListener(1986);

            // Start the TCP listener and listen for connections
            tlsClient.Start();

            // The while loop will check for true in this before checking for connections
            ServRunning = true;

            // Start the new tread that hosts the listener
            thrListener = new Thread(KeepListening);
            thrListener.Start();
        }



        private void KeepListening()
        {

            // While the server is running
            while (ServRunning == true)
            {

                // Accept a pending connection
                tcpClient = tlsClient.AcceptTcpClient();

                // Create a new instance of Connection
                Connection newConnection = new Connection(tcpClient); newConnection = new Connection(tcpClient);
            }
        }
    }
    
    // This class handels connections; there will be as many instances of it as there will be connected users
    class Connection
    {
        TcpClient tcpClient;
        // The thread that will send information to the client
        private Thread thrSender;
        private StreamReader srReceiver;
        private StreamWriter swSender;
        private string currUser;
        private string strResponse;

        // The constructor of the class takes in a TCP connection
        public Connection(TcpClient tcpCon)
        {
            tcpClient = tcpCon;
            // The thread that accepts the client and awaits messages
            thrSender = new Thread(AcceptClient);
            // The thread calls the AcceptClient() method
            thrSender.Start();
        }

        private void CloseConnection()
        {
            // Close the currently open objects
            tcpClient.Close();
            srReceiver.Close();
            swSender.Close();
        }

        // Occures when a new client is accepted
        private void AcceptClient()
        {
            srReceiver = new System.IO.StreamReader(tcpClient.GetStream());
            swSender = new System.IO.StreamWriter(tcpClient.GetStream());

            // Read the account information from the client
            currUser = srReceiver.ReadLine();

            // We got a response from the client
            if (currUser != "")
            {
                // Store the user name in the hash table
                if (ChatServer.htUsers.Contains(currUser) == true)
                {
                    // 0 means not connected
                    swSender.WriteLine("0|This username already exists.");
                    swSender.Flush();
                    CloseConnection();
                    return;
                }
                else if (currUser == "Administrator")
                {
                    // 0 means not connected
                    swSender.WriteLine("0|This username is reserved.");
                    swSender.Flush();
                    CloseConnection();
                    return;
                }
                else
                {
                    // 1 means connected successfully
                    swSender.WriteLine("1");
                    swSender.Flush();

                    // Add the user to the hash tables and start listening for messages from him
                    ChatServer.AddUser(tcpClient, currUser);
                }
            }
            else
            {
                CloseConnection();
                return;
            }

            try
            {
                // Keep waiting for a message from the user
                while ((strResponse = srReceiver.ReadLine()) != "")
                {
                    // If it's invalid, remove the user
                    if (strResponse == null)
                    {
                        ChatServer.RemoveUser(tcpClient);
                    }
                    else
                    {
                        // Otherwise send the message to all the other users
                        ChatServer.SendMessage(currUser, strResponse);
                    }
                }
            }
            catch
            {
                // If anything went wrong with this user, disconnect him
                ChatServer.RemoveUser(tcpClient);
            }
        }
    }
   


}



Now this is all about Server chat.. Now I will give Client chat:
XAML Code:
<pre lang="xml"><Window x:Class="chatclientwpf.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="597" Width="552">
    <Grid>
        <Label Height="27" Name="label1" VerticalAlignment="Top" HorizontalAlignment="Left" Width="60">Server IP:</Label>
        <TextBox Height="23" Margin="92,4,166,0" Name="txtIp" VerticalAlignment="Top">192.168.1.3</TextBox>
        <Label Height="28" HorizontalAlignment="Left" Margin="0,51,0,0" Name="label2" VerticalAlignment="Top" Width="70">User Name:</Label>
        <TextBox Height="23" Margin="92,51,166,0" Name="txtUser" VerticalAlignment="Top">Aditya</TextBox>
        <Button Height="23" HorizontalAlignment="Right" Margin="0,51.138,70,0" Name="btnConnect" VerticalAlignment="Top" Width="75" Click="btnConnect_Click">Connect</Button>
        <TextBox Margin="27,99,59,178" Name="txtLog" IsEnabled="False" VerticalScrollBarVisibility="Visible" />
        <TextBox Height="57" Margin="27,0,144,79" Name="txtMessage" VerticalAlignment="Bottom" VerticalScrollBarVisibility="Auto"/>
        <Button Height="36" HorizontalAlignment="Right" Margin="0,0,59,90" Name="btnSend" VerticalAlignment="Bottom" Width="75" Click="btnSend_Click">Send</Button>
    </Grid>
</Window

>



C# coding:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;

namespace chatclientwpf
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    
    public partial class Window1 : Window
    {
        public Window1()
        {
            // On application exit, don't forget to disconnect first

            //Application.ApplicationExit += new EventHandler(OnApplicationExit);

           

            InitializeComponent();
        }
        
        // Will hold the user name
        private string UserName = "Unknown";
        private StreamWriter swSender;
        private StreamReader srReceiver;
        private TcpClient tcpServer;

        // Needed to update the form with messages from another thread
        private delegate void UpdateLogCallback(string strMessage);

        // Needed to set the form to a "disconnected" state from another thread
        private delegate void CloseConnectionCallback(string strReason);
        private Thread thrMessaging;
        private IPAddress ipAddr;
        private bool Connected;

        private void btnConnect_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                // If we are not currently connected but awaiting to connect
            if (Connected == false)
            {
                // Initialize the connection
                InitializeConnection();
            }
            else // We are connected, thus disconnect
            {
                CloseConnection("Disconnected at user's request.");
            }
            }
        catch (Exception ex)
            {
                MessageBox.Show("Error :"+ex);
            }
        }
        private void InitializeConnection()
        {

           try
           {
            // Parse the IP address from the TextBox into an IPAddress object
            ipAddr = IPAddress.Parse(txtIp.Text);

            // Start a new TCP connections to the chat server
            tcpServer = new TcpClient();
            tcpServer.Connect(ipAddr, 1986);

            // Helps us track whether we're connected or not
            Connected = true;

            // Prepare the form
            UserName = txtUser.Text;

            // Disable and enable the appropriate fields
            
            txtIp.IsEnabled = false;
            txtUser.IsEnabled = false;
            txtMessage.IsEnabled = true;
            btnSend.IsEnabled = true;
            btnConnect.Content = "Disconnect";

            // Send the desired username to the server
            swSender = new StreamWriter(tcpServer.GetStream());
            swSender.WriteLine(txtUser.Text);
            swSender.Flush();

            // Start the thread for receiving messages and further communication
            thrMessaging = new Thread(new ThreadStart(ReceiveMessages));
            thrMessaging.Start();
        }
            catch (Exception ex)
            {
                MessageBox.Show("Error :"+ex);
            }
        }

        // This method is called from a different thread in order to update the log TextBox

        private void UpdateLog(string strMessage)
        {
            // Append text also scrolls the TextBox to the bottom each time
            txtLog.AppendText(strMessage + "\r\n");
        }

        private void btnSend_Click(object sender, RoutedEventArgs e)
        {
            SendMessage();
        }
        // But we also want to send the message once Enter is pressed



        private void txtMessage_KeyDown(object sender, KeyEventArgs e )
        {
            // If the key is Enter
            
            if (e.Key == Key.Enter)
            {
                SendMessage();
            }
        }
        
        // Sends the message typed in to the server
        private void SendMessage()
        {


            if (txtMessage.LineCount >= 1)
            {
                swSender.WriteLine(txtMessage.Text);
                swSender.Flush();
                // txtMessage.Lines = null;
            }
            txtMessage.Text = "";
        }

        // Closes a current connection
        private void CloseConnection(string Reason)
        {
            try
            {
                // Show the reason why the connection is ending
                txtLog.AppendText(Reason + "\r\n");

                // Enable and disable the appropriate controls on the form
                txtIp.IsEnabled = true;
                txtUser.IsEnabled = true;
                txtMessage.IsEnabled = false;
                btnSend.IsEnabled = false;
                btnConnect.Content = "Connect";

                // Close the objects
                Connected = false;
                swSender.Close();
                srReceiver.Close();
                tcpServer.Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error :"+ex);
            }
        }

        public void OnApplicationExit(object sender, EventArgs e)
        {
            if (Connected == true)
            {
                // Closes the connections, streams, etc.
                Connected = false;
                swSender.Close();
                srReceiver.Close();
                tcpServer.Close();
            }
        }
        private void ReceiveMessages()
        {
            // Receive the response from the server
            srReceiver = new StreamReader(tcpServer.GetStream());

            // If the first character of the response is 1, connection was successful
            string ConResponse = srReceiver.ReadLine();

            // If the first character is a 1, connection was successful
            if (ConResponse[0] == '1')
            {
                // Update the form to tell it we are now connected
                this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,new UpdateLogCallback(this.UpdateLog), new object[] { "Connected Successfully!" });
            }

            else // If the first character is not a 1 (probably a 0), the connection was unsuccessful
            {
                string Reason = "Not Connected: ";

                // Extract the reason out of the response message. The reason starts at the 3rd character
                Reason += ConResponse.Substring(2, ConResponse.Length - 2);

                // Update the form with the reason why we couldn't connect
                this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new CloseConnectionCallback(this.CloseConnection), new object[] { Reason });

                // Exit the method
                return;
            }

            // While we are successfully connected, read incoming lines from the server
            while (Connected)
            {
                // Show the messages in the log TextBox
                //this.Invoke(new UpdateLogCallback(this.UpdateLog), new object[] { srReceiver.ReadLine() });
                this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new UpdateLogCallback(this.UpdateLog), new object[] { srReceiver.ReadLine() });
            }

        }

    }//Window1...
}//namespace



I am getting error at Invoke method. Please study this code and suggest me changes where ever necessary..
Thanks.
Posted
Updated 27-Apr-11 19:30pm
v2
Comments
Kim Togo 28-Apr-11 2:53am    
There are 4 places in the code where .Invoke is used. Can you be more specific?
Nagy Vilmos 28-Apr-11 6:26am    
Either try debugging, you know stepping through line-by-line, or add some loggging into your code to allow you to see the flow.
Manfred Rudolf Bihy 28-Apr-11 10:25am    
I'm truely sorry, but I don't think anybody will wade through all that code. As my predecessors have already pointed out:

1. You said there was an error/exception: Please add all the details of said error/exception to your question.

2. Use debugging and/or loggin to pin point your problem.
3. Don't tell us what you expect of us to do for you, but rather formulate a question we can answer to.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900