I have created a C# Windows Forms application which I've attempted to make as simple as possible to demonstrate a problem I am running into. I'm trying to use a DataGridView to allow user input in one column while simultaneously getting updates in another column from a background thread.
The problem is that the Input column is effectively un-editable because -- I think -- the updates which are intended for the Output column cause the Input column to be updated with it's current value while the user is attempting to change it.
Is this a bug in DataGridView? Is there a better way to do this sort of thing? Can anyone recommend a good workaround?
The following code demonstrates the problem. The Output column will continuously update and the Input column is virtually uneditable. I've merged the designer code (Form1.designer.cs), and Main (from Program.cs) into the form code (Form1.cs) -- so the following code should work on its own.
using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Timers;
public partial class Form1 : Form
{
private System.ComponentModel.IContainer components = null;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.dataGridView = new System.Windows.Forms.DataGridView();
((System.ComponentModel.ISupportInitialize)(this.dataGridView)).BeginInit();
this.SuspendLayout();
//
// dataGridView
//
this.dataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.dataGridView.Location = new System.Drawing.Point(3, 12);
this.dataGridView.Name = "dataGridView";
this.dataGridView.RowTemplate.Height = 24;
this.dataGridView.Size = new System.Drawing.Size(322, 158);
this.dataGridView.TabIndex = 0;
//
// Form1
//
this.Au开发者_JAVA百科toScaleDimensions = new System.Drawing.SizeF(8F, 16F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(328, 174);
this.Controls.Add(this.dataGridView);
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
((System.ComponentModel.ISupportInitialize)(this.dataGridView)).EndInit();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.DataGridView dataGridView;
public Form1()
{
InitializeComponent();
}
BindingSource bindingSource = new BindingSource();
BindingList<Item> items = new BindingList<Item>();
private System.Timers.Timer timer;
private void Form1_Load(object sender, EventArgs e)
{
dataGridView.DataSource = bindingSource;
bindingSource.DataSource = items;
items.Add(new Item(dataGridView));
timer = new System.Timers.Timer {Interval = 50};
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Start();
}
private Random random = new Random();
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
items[0].SetOutput(random.Next(100));
}
}
class Item : INotifyPropertyChanged
{
public int Input { get; set; }
private int output;
public int Output
{
get { return output; }
private set
{
output = value;
OnPropertyChanged("Output");
}
}
public Control control;
public Item(Control control)
{
this.control = control;
}
public void SetOutput(int outputValue)
{
Output = outputValue;
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
if(!control.IsDisposed)
control.BeginInvoke(handler, this, new PropertyChangedEventArgs(name));
}
}
}
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
I suspect that when a PropertyChanged
event occurs, the DataGridView
refreshes all cells, or perhaps only cells in the row that changed (does it happen when you're editing another row ?), losing all uncommited changes.
If you can intercept the event before the DataGridView
refreshes the cells, you could save the uncommited changes away to restore them after the refresh. But that would be an ugly workaround...
Did you ask on the MSDN forums ? Maybe someone from MS could give you a more useful answer
Maybe the cell being edited is losing focus? Perhaps each time you update the other column, store where you were editing, and reset the focus after the update?
try to update the column not in 50 milisecond but in somthing like intervale equal to 4000 its work for me icould change the value in the other column and still get change on the other column
精彩评论