代码之家  ›  专栏  ›  技术社区  ›  Brendan

向绑定到DataGridView的DataTable添加列不会更新该视图

  •  4
  • Brendan  · 技术社区  · 17 年前

    我有一个数据表,它由一个csv文件填充,然后使用一个DataGridView,在内存中编辑数据。据我所知,数据的编程编辑应该在用户编辑通过的数据表上完成。数据报视图。

    但是,当我以编程方式向数据表添加列时,它不会自动反映在DataGridView中,我怀疑反过来也是正确的。

    如何保持这两个并发?我认为数据绑定的想法是这是自动的…

    这是相关的设置代码- WorksheetGridView 子类 DataGridView

    // Can access data directly
    public DataTable data = new DataTable();
    
    public WorksheetGridView()
    {
        InitializeComponent();
    
        // Allow copying from table to clipboard
        this.ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableWithoutHeaderText;
    
        // TODO: how to allow both row and column selects?
        //this.SelectionMode = DataGridViewSelectionMode.ColumnHeaderSelect;
    
        // Load up a blank DataTable to hold user inputted data
        int i;
        const int numBlankRows = Config.Application.DefaultNumRows;
        const int numBlankCols = Config.Application.DefaultNumCols;
        // TODO: Figure out how to include this as a config variable
        DBNull dfltCellContent = DBNull.Value;
        DataRow tmpRow;
        // Add columns - i used for naming
        for (i = 0; i < numBlankCols; i++)
        {
            this.AddColumn(i);
        }
    
        // Add rows
        for (i = 0; i < numBlankRows; i++)
        {
           tmpRow = this.data.NewRow();
           // Fill cells with something (i.e. blank cells)
           foreach (DataColumn col in this.data.Columns)
           {
               tmpRow[col.ColumnName] = DBNull.Value;
           }
           this.data.Rows.Add(tmpRow);
        }
        // Link data to the view
        this.DataSource = this.data;
    }
    
    private void AddColumn(int colIndex)
    {
        // Adds a column to the data array
        DataColumn tmpCol;
        tmpCol = new DataColumn();
        tmpCol.DataType = Type.GetType(Config.Application.DataType);
        tmpCol.ColumnName = "C" + colIndex.ToString();
        tmpCol.ReadOnly = false;
        tmpCol.Unique = false;
        tmpCol.AllowDBNull = true;
        this.data.Columns.Add(tmpCol);
    }
    

    不起作用的是我打电话的时候 AddColumn 例如,在该代码中处理粘贴制表符分隔的数据,

    public void PasteToCells(string mode)
    {
        // TODO: Write paste code
        int i;
        if (Clipboard.ContainsText())
        {
            string clipBoardContent = Clipboard.GetText();
            using (CsvReader pastedCsvReader = new CsvReader(
                new StringReader(clipBoardContent), false, '\t'))
            {
                // TODO: If more rows/cols than in data table then expand accordingly
                int numPastedCols = pastedCsvReader.FieldCount;
                int currRowIndex, currColumnIndex;
                GetSelectedInsertPoint(out currRowIndex, out currColumnIndex);
                // Make space for columns if needed
                if (mode == "insertcols")
                {
                    int baseIndex = this.data.Columns.Count;
                    for (i = 0; i < numPastedCols; i++)
                    {
                        //this.Columns.Add
                        // TODO: Doesn't work yet - do you edit the DataGridView and reflect to DataTable or vise-versa?
                        this.AddColumn(baseIndex + i);
                    }
                }
                while  (pastedCsvReader.ReadNextRecord()) 
                {
                    // Make space for rows (row by row) if needed
                    if (mode == "insertrows")
                    {
                        this.data.NewRow();
                        // TODO: Add a row
                    }
                    // Populate the cells with valid pasted text
                    for (i = 0; i < numPastedCols; i++)
                    {
                        this.data.Rows[currRowIndex][currColumnIndex + i] = ConvertCellContent(pastedCsvReader[i]);
                    }
                    currRowIndex = currRowIndex + 1;
                }
            }
        }
        else
        {
            // TODO: Do nothing?
            Console.WriteLine("No text on clipboard");
        }
    }
    

    我尝试了下面给出的例子,它确实有效。但是,当我尝试这样做时,水平滚动条会短暂地展开和收缩,但子类中的表除外。 数据表格控件 未更新。
    不过,该列位于 DataTable 但是-例如,我不能添加相同名称的列,列计数也反映了额外的列。是否有可能限制 数据表格控件 ?

    添加行也可以。

    解决了的:

    这个 AutoGeneratedColumns 被设定为 false 在设计器代码中 true 在属性对话框中(并在代码中显式设置)。最初的列是以编程方式生成的,因此不应该出现,但由于设计器代码也继续生成最初用于调试的“designed in”列,因此没有出现这种情况。

    道德:检查自动生成的代码!

    除此之外,请参见 this post this post

    4 回复  |  直到 7 年前
        1
  •  2
  •   Jimi    7 年前

    听起来不太对劲。为了测试它,我编写了一个简单的应用程序,它创建一个数据表并向其中添加一些数据。
    button1.Click 它将表绑定到DataGridView。
    然后,我添加了第二个按钮,单击该按钮时,会将另一列添加到基础数据表中。
    当我测试它时,我单击了第二个按钮,网格立即反映了更新。

    为了测试相反的情况,我添加了第三个按钮,它弹出一个对话框,其中包含绑定到同一个数据表的DataGridView。在运行时,我向第一个DataGridView添加了一些值,当我单击按钮打开对话框时,这些更改被反映出来。

    我的观点是,它们应该保持同步。马克建议你检查一下 AutoGenerateColumns 设置为 true . 不过,您不需要调用DataBind,这只适用于Web上的DataGridView。也许你可以把你正在做的事贴出来,因为这是可行的。

    我如何测试它:

    DataTable table = new DataTable();
    public Form1()
    {
        InitializeComponent();
    }
    
    private void button1_Click(object sender, EventArgs e)
    {
        table.Columns.Add("Name");
        table.Columns.Add("Age", typeof(int));
        table.Rows.Add("Alex", 26);
        table.Rows.Add("Jim", 36);
        table.Rows.Add("Bob", 34);
        table.Rows.Add("Mike", 47);
        table.Rows.Add("Joe", 61);
    
        this.dataGridView1.DataSource = table;
    }
    
    private void button2_Click(object sender, EventArgs e)
    {
        table.Columns.Add("Height", typeof(int));
        foreach (DataRow row in table.Rows)
        {
            row["Height"] = 100;
        }
    }
    
    private void button3_Click(object sender, EventArgs e)
    {
        GridViewer g = new GridViewer { DataSource = table };
        g.ShowDialog();
    }
    
    public partial class GridViewer : Form //just has a DataGridView on it
    {
        public GridViewer()
        {
        InitializeComponent();
        }
    
        public object DataSource
        {
            get { return this.dataGridView1.DataSource; }
            set { this.dataGridView1.DataSource = value; }
        }
    }
    
        2
  •  1
  •   Mark Brittingham    17 年前

    AutoGenerateColumns是否设置为true?如果在初始绑定之后进行更改,则还必须调用databind()重新绑定更改的数据源。我知道Ajax回调是这样的,我 认为 这对于WinForms控件回发是正确的。

        3
  •  1
  •   Community Mohan Dere    9 年前

    这里还有另一个解决方案,您不需要为数据网格分配“名称”,这样数据网格就可以是一个模板元素。

    (在我的例子中,数据网格是tabControl.ContentTemplate中的模板元素)

    显示新列(在初始绑定后以编程方式添加)的键正在强制数据报刷新。 从答案中 Force WPF DataGrid to regenerate itself ,Andres建议设置 AutoGenerateColumns 从假到真将强制数据报刷新。

    这意味着我只需要:

    1. 绑定 自动生成列 到我的对象的一个属性
    2. 在添加列之前将属性设置为false
    3. 在添加列后将属性设置为true。

    代码如下:

    XAML:

    <DataGrid AutoGenerateColumns="{Binding toggleToRefresh}"
              ItemsSource="{Binding dataTable}"
              />
    

    C:

     public class MyTabItem : ObservableObject 
     {
            private DataTable _dataTable = new DataTable();
            public DataTable dataTable
            {
                get { return _dataTable; }
            }
    
            private bool _toggleToRefresh = true;
            public bool toggleToRefresh
            {
                get { return _toggleToRefresh; }
                set
                {
                    if (_toggleToRefresh != value)
                    {
                        _toggleToRefresh = value;
                        RaisePropertyChanged("toggleToRefresh");
                    }
                }
            }
    
            public void addDTColumn()
            {
                toggleToRefresh = false;
                string newColumnName = "x" + dataTable.Columns.Count.ToString();
                dataTable.Columns.Add(newColumnName, typeof(double));
                foreach (DataRow row in dataTable.Rows)
                {
                    row[newColumnName] = 0.0;
                }
                toggleToRefresh = true;
            }
    
            public void addDTRow()
            {
                var row = dataTable.NewRow();
                foreach (DataColumn col in dataTable.Columns)
                {
                    row[col.ColumnName] = 0.0;
                }
                dataTable.Rows.Add(row);
            }
     }
    

    希望能帮上忙:)

        4
  •  -1
  •   SnapJag    17 年前

    我也有同样的问题,我发布了一个databind()。这不是万能的银弹,但它在某些情况下帮助了我。在通过DataView捕获信息之前,在EditCommand和UpdateCommand事件之后,在EditItemIndex语句之后,

    protected void datalistUWSolutions_EditCommand(object source, DataListCommandEventArgs e)
    {
      datalistUWSolutions.EditItemIndex = e.Item.ItemIndex;
      datalistUWSolutions.DataBind(); // refresh the grid.
    }
    

    protected void datalistUWSolutions_UpdateCommand(object source, DataListCommandEventArgs e)
    {
      objDSSolutions.UpdateParameters["Name"].DefaultValue = ((Label)e.Item.FindControl("lblSolutionName")).Text;
      objDSSolutions.UpdateParameters["PriorityOrder"].DefaultValue = ((Label)e.Item.FindControl("lblOrder")).Text;
      objDSSolutions.UpdateParameters["Value"].DefaultValue = ((TextBox)e.Item.FindControl("txtSolutionValue")).Text;
      objDSSolutions.Update();
      datalistUWSolutions.EditItemIndex = -1; // Release the edited record
      datalistUWSolutions.DataBind();         // Redind the records for refesh the control
    }