DataGridView的 - 同时输入和输出 - 这是在DataGridView中的错误这是、错误、DataGridView

2023-09-03 16:57:36 作者:扬言不负你

我创建了一个C#Windows窗体我已经试图做出尽可能的简单证明我遇到了一个问题中的应用。我试图用一个DataGridView允许用户输入一列,同时获取更新另一列从后台线程。

的问题是,在输入列是有效不可编辑,因为 - 我认为 - 这旨在用于输出列中的更新造成的输入栏被更新与它的当前值,而用户试图去改变它

这是在DataGridView中的一个错误?有没有更好的方式做这样的事情?谁能推荐一个好的解决办法?

下面code演示了此问题。输出列将不断更新和输入列几乎是不可编辑的。我已经合并了设计师code(Form1.designer.cs),和主要(从Program.cs中)到表单code(Form1.cs中) - 所以下面code应该工作它自己。

 使用系统;
使用System.ComponentModel;
使用System.Windows.Forms的;
使用System.Timers;

公共部分类Form1中:形态
{
    私人System.ComponentModel.IContainer成分= NULL;

    保护覆盖无效的Dispose(BOOL处置)
    {
        如果(处置和放大器;&安培;!(成分= NULL))
        {
            components.Dispose();
        }
        base.Dispose(处置);
    }

    #region Windows窗体设计器生成的code

    ///<总结>
    ///设计器支持所需的方法 - 不要修改
    ///此方法的code编辑器的内容。
    ///< /总结>
    私人无效的Ini​​tializeComponent()
    {
        this.dataGridView =新System.Windows.Forms.DataGridView();
        ((System.ComponentModel.ISupportInitialize)(this.dataGridView))BeginInit在()。
        this.SuspendLayout();
        //
        //的dataGridView
        //
        this.dataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
        this.dataGridView.Location =新System.Drawing.Point(3,12);
        this.dataGridView.Name =的dataGridView;
        this.dataGridView.RowTemplate.Height = 24;
        this.dataGridView.Size =新System.Drawing.Size(322,158);
        this.dataGridView.TabIndex = 0;
        //
        // Form1中
        //
        this.AutoScaleDimensions =新System.Drawing.SizeF(8F,16F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.ClientSize =新System.Drawing.Size(328,174);
        this.Controls.Add(this.dataGridView);
        this.Name =Form1的;
        this.Text =Form1的;
        this.Load + =新System.EventHandler(this.Form1_Load);
        ((System.ComponentModel.ISupportInitialize)(this.dataGridView))EndInit()。
        this.ResumeLayout(假);

    }

    #endregion

    私人System.Windows.Forms.DataGridView的dataGridView;

    公共Form1中()
    {
        的InitializeComponent();
    }

    的BindingSource BindingSource的=新的BindingSource();
    的BindingList<项目>项目=新的BindingList<项目>();
    私人System.Timers.Timer的定时器;
    私人无效Form1_Load的(对象发件人,EventArgs的)
    {
        dataGridView.DataSource = BindingSource的;
        bindingSource.DataSource =项目;
        items.Add(新项目(的dataGridView));

        定时器=新System.Timers.Timer的{间隔= 50};
        timer.Elapsed + =新ElapsedEventHandler(timer_Elapsed);
        timer.Start();
    }

    私人随机随机=新的随机();
    无效timer_Elapsed(对象发件人,ElapsedEventArgs E)
    {
        项[0] .SetOutput(random.Next(100));
    }
}


类项目:INotifyPropertyChanged的
{
    公众诠释输入{获得;组; }

    私人诠释输出;
    公众诠释输出
    {
        {返回输出; }
        私定
        {
            输出=值;
            OnPropertyChanged(输出);
        }
    }

    公共管理控制;

    公共项目(控制控制)
    {
        this.control =控制;
    }

    公共无效SetOutput(INT输出值)
    {
        输出=输出值;
    }

    公共事件PropertyChangedEventHandler的PropertyChanged;

    保护无效OnPropertyChanged(字符串名称)
    {
        PropertyChangedEventHandler处理器=的PropertyChanged;
        如果(处理!= NULL)
        {
            如果(!control.IsDisposed)
                control.BeginInvoke(处理器,这一点,新PropertyChangedEventArgs(名称));
        }
    }
}

静态类节目
{
    ///<总结>
    ///的主入口点的应用程序。
    ///< /总结>
    [STAThread]
    静态无效的主要()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(假);
        Application.Run(新Form1中());
    }
}
 

解决方案

我怀疑,当的PropertyChanged 事件发生时,的DataGridView 刷新所有单元格,或改变了行中也许只有细胞(它,当你正在编辑另一行发生?),丢失所有未提交的更改。

当控件被数据绑定时,无法以编程方式向DatagridView的行集合中添加行,怎么解决

如果你能拦截的DataGridView 在活动前刷新细胞,能省则未提交的变化而去刷新后恢复。但是,这将是一个丑陋的解决办法...

你问在MSDN论坛?也许有人从MS可以给你一个更加有用的答案

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.AutoScaleDimensions = 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