Windows Forms:点击Timer窗体按钮后更新主窗体DataGridView指定单元格值
Hey there! Let's work through this together—since you're dealing with WinForms (given the Forms and DataGridView references), here are a couple of solid approaches to get that value from your Timer form into your main form's DataGridView and make sure it displays correctly:
This is the cleanest way because it avoids tight coupling between your Timer form and main form—great for maintainability.
Step 1: Define an event in your Timer form
First, create a custom event to broadcast when a new value is ready, plus an event args class to pass the value and target cell coordinates:
// Inside your TimerForm class public event EventHandler<ValueUpdatedEventArgs> ValueUpdated; // Custom event args to carry your data public class ValueUpdatedEventArgs : EventArgs { public object NewValue { get; } public int TargetRow { get; } public int TargetColumn { get; } public ValueUpdatedEventArgs(object newValue, int targetRow, int targetColumn) { NewValue = newValue; TargetRow = targetRow; TargetColumn = targetColumn; } }
Step 2: Trigger the event when you get the value
When your Timer form captures the value you want to send, fire the event:
// Example: In your Timer's Tick event or value-retrieval method private void Timer1_Tick(object sender, EventArgs e) { // Replace this with your actual value and target cell indices object newValue = 42; // Your fetched value int targetRow = 0; // Specific row index int targetCol = 2; // Specific column index // Fire the event (safe even if no subscribers) ValueUpdated?.Invoke(this, new ValueUpdatedEventArgs(newValue, targetRow, targetCol)); }
Step 3: Subscribe to the event in your main form
When you open the Timer form from your main form, hook up the event handler:
// Inside your MainForm's code (e.g., a button click that opens TimerForm) private void OpenTimerFormBtn_Click(object sender, EventArgs e) { var timerForm = new TimerForm(); // Subscribe to the value update event timerForm.ValueUpdated += TimerForm_OnValueUpdated; timerForm.Show(); // Use ShowDialog() if you want a modal form }
Step 4: Update the DataGridView from the main form
Handle the event, making sure you're on the UI thread (critical to avoid cross-thread exceptions):
private void TimerForm_OnValueUpdated(object sender, ValueUpdatedEventArgs e) { // Check if we need to switch to the UI thread if (dataGridView1.InvokeRequired) { // Invoke the update on the UI thread dataGridView1.Invoke(new Action(() => UpdateDataGridViewCell(e))); return; } UpdateDataGridViewCell(e); } private void UpdateDataGridViewCell(ValueUpdatedEventArgs e) { // Validate indices to avoid out-of-bounds errors if (e.TargetRow >= 0 && e.TargetRow < dataGridView1.RowCount && e.TargetColumn >= 0 && e.TargetColumn < dataGridView1.ColumnCount) { // Set the cell value dataGridView1.Rows[e.TargetRow].Cells[e.TargetColumn].Value = e.NewValue; // Force immediate refresh of the cell (usually optional, but fixes edge cases) dataGridView1.RefreshEdit(); } }
If you're working on a small app and don't mind tight coupling, you can pass a reference to the main form to the Timer form:
Step 1: Modify TimerForm's constructor
private readonly MainForm _mainForm; public TimerForm(MainForm mainForm) { InitializeComponent(); _mainForm = mainForm; }
Step 2: Add a public update method to MainForm
// Inside MainForm public void UpdateDataGridViewCell(object newValue, int rowIndex, int colIndex) { if (dataGridView1.InvokeRequired) { dataGridView1.Invoke(new Action(() => UpdateCellInternal(newValue, rowIndex, colIndex))); return; } UpdateCellInternal(newValue, rowIndex, colIndex); } private void UpdateCellInternal(object newValue, int rowIndex, int colIndex) { if (rowIndex >= 0 && rowIndex < dataGridView1.RowCount && colIndex >= 0 && colIndex < dataGridView1.ColumnCount) { dataGridView1.Rows[rowIndex].Cells[colIndex].Value = newValue; dataGridView1.RefreshEdit(); } }
Step 3: Call the method from TimerForm
// Inside TimerForm's value-retrieval logic _mainForm.UpdateDataGridViewCell(newValue, targetRow, targetCol);
- Cross-thread safety: Always check
InvokeRequired! If you're usingSystem.Timers.Timer, its events fire on a background thread—skipping this will throw an exception.System.Windows.Forms.Timerruns on the UI thread, but adding the check makes your code robust. - Data-bound grids: If your DataGridView is bound to a
DataTableor other data source, update the source directly instead of the cell (e.g.,yourDataTable.Rows[rowIndex]["ColumnName"] = newValue;). The grid will auto-reflect changes. - Index validation: Always check that your row/column indices are within bounds to avoid crashes.
内容的提问来源于stack exchange,提问作者MaxB

