Inter-Form Communication in C# WinForms
Parent-Child Form Communication
1. Pass Values with Public Static Variables
Main form (MainForm) code:
public partial class MainForm : Form
{
// Declare a public static variable to hold station ID
public static string stationId = string.Empty;
// Assign value to the static variable during initialization
public MainForm()
{
InitializeComponent();
stationId = "q13bh01-bh12";
}
}
Child form (GroupForm) code:
private void GroupForm_Load(object sender, EventArgs e)
{
// Read value from the main form's static variable
txtStationId.Text = MainForm.stationId.Trim();
// Update the static variable for other forms to access
MainForm.stationId = "q13bh01-bh11";
}
This approach supports bidirectional value passing and is very simple to implement. The downside is that static variable are allocated memory when the class is loaded, stored in the method area, and are rarely destroyed automatically. If the runtime garbage collects static memory when system memory is low, it can lead to invalid access errors.
2. Pass Values with Public Instance Variables
Main form (MainForm) code:
public partial class MainForm : Form
{
// Declare public instance variable for station ID
public string stationId = string.Empty;
public MainForm()
{
InitializeComponent();
stationId = "q13bh01-bh12";
}
// Open child form when button is clicked
private void openGroupBtn_Click(object sender, EventArgs e)
{
GroupForm groupForm = new GroupForm();
// Pass value before showing the dialog, order is critical
groupForm.inputStationId = this.stationId;
groupForm.ShowDialog();
}
}
Child form (GroupForm) code:
public partial class GroupForm : Form
{
// Define public property to receive passed value
public string inputStationId = string.Empty;
}
This approach is simple to implement, and only supports unidirectional passing from the parent form to the child form.
3. Pass Values with Custom Events
First define a custom event argument class to carry data:
public class MessageUpdatedEventArgs : EventArgs
{
public string MessageContent { get; set; }
}
Child form implementation:
public partial class GroupForm : Form
{
public GroupForm()
{
InitializeComponent();
}
// Update display with new message
private void UpdateDisplay(string content)
{
mainTextBox.Text = content;
mainTextBox.Refresh();
}
// Event handler to process message from parent form
public void OnParentMessageSent(object sender, EventArgs e)
{
var eventArgs = e as MessageUpdatedEventArgs;
if (eventArgs != null)
{
UpdateDisplay(eventArgs.MessageContent);
}
}
}
Main form implementation:
public partial class MainForm : Form
{
// Define custom event for message sending
public event EventHandler MessageSent;
public MainForm()
{
InitializeComponent();
}
// Trigger event when send button is clicked
private void sendContentBtn_Click(object sender, EventArgs e)
{
MessageSent?.Invoke(this, new MessageUpdatedEventArgs
{
MessageContent = inputTextBox.Text
});
}
private void openChildGroupBtn_Click(object sender, EventArgs e)
{
GroupForm childForm = new GroupForm();
// Subscribe child's handler to parent's event
MessageSent += childForm.OnParentMessageSent;
childForm.Show();
}
}
This approach is ideal for real-time data passing between forms.
Communication Between Non-Parent-Child Forms
A commmon implementation for cross communication between unrelated forms in networked applications uses a shared message listener that propagates received messages to target forms. The following example shows a typical socket-based message receiving flow that updates the UI:
/// <summary>
/// Listens for incoming connections and processes incoming messages from remote endpoints
/// </summary>
private void StartListener(Socket listenerSocket)
{
while (true)
{
// Spin up a background task to handle incoming messages
Task.Run(() => ReceiveIncomingMessage(listenerSocket));
}
}
/// <summary>
/// Continuously receives messages from the connected client socket
/// </summary>
private void ReceiveIncomingMessage(Socket clientSocket)
{
byte[] buffer = new byte[4 * 1024 * 1024];
while (true)
{
try
{
int receivedLength = clientSocket.Receive(buffer);
if (receivedLength > 0 && buffer[0] == 0)
{
// Decode the message content from the buffer
string message = Encoding.UTF8.GetString(buffer, 1, receivedLength - 1);
string fullMessage = $"{clientSocket.RemoteEndPoint}: {message}";
// Invoke UI update on the main UI thread
logTextBox.Invoke(new Action<string>(AppendLogEntry), fullMessage);
}
}
catch
{
throw;
}
Thread.Sleep(1000);
}
}
/// <summary>
/// Appends a new log entry to the UI text box
/// </summary>
private void AppendLogEntry(string logText)
{
logTextBox.AppendText(logText + Environment.NewLine);
}