Добавление столбцов в DataTable, привязанное к DataGridView, не обновляет представление - PullRequest
4 голосов
/ 29 января 2009

У меня есть DataTable, который затем заполняется из файла CSV, с помощью DataGridView данные редактируются в памяти. Насколько я понимаю, программное редактирование данных должно выполняться в DataTable, где пользовательское редактирование выполняется через. DataGridView.

Однако когда я программно добавляю столбцы в DataTable, он не отражается автоматически в 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");
    }
}

Я попробовал приведенный ниже пример, и он работает. Однако, когда я пытаюсь это сделать, горизонтальная полоса прокрутки кратковременно расширяется и сжимается, но таблица в подклассе DataGridView не обновляется.
Однако столбец находится в DataTable - например, я не могу добавить столбец с тем же именем, число столбцов также отражает дополнительные столбцы. Возможно, есть вариант конструктора, который может ограничить обновление DataGridView?

Также хорошо работает добавление строк.

РЕШИТЬ:

Для AutoGeneratedColumns было установлено значение false в коде конструктора, несмотря на то, что оно было true в диалоге свойств (и задано явно в коде). Начальные столбцы были сгенерированы программно и поэтому не должны были появляться, однако это не было обнаружено, поскольку код конструктора также продолжал генерировать столбцы «сконструированы в», которые первоначально использовались для отладки.

Мораль: проверьте автоматически сгенерированный код!

В дополнение к этому см. этот пост и этот пост

Ответы [ 4 ]

2 голосов
/ 29 января 2009

Это не звучит правильно. Чтобы проверить это, я написал простое приложение, которое создает DataTable и добавляет к нему некоторые данные.
На button1.Click он связывает таблицу с DataGridView.
Затем я добавил вторую кнопку, которая при нажатии добавляет еще один столбец в базовую таблицу данных.
Когда я протестировал его и нажал вторую кнопку, сетка immedialtey отразила обновление.

Чтобы проверить обратное, я добавил третью кнопку, которая открывает диалоговое окно с DataGridView, которое привязывается к тому же DataTable. Во время выполнения я добавил некоторые значения в первый DataGridView, и когда я нажал кнопку, чтобы открыть диалоговое окно, изменения были отражены.

Суть в том, что они должны оставаться параллельными. Марк может быть прав, когда он предложил вам проверить, установлено ли AutoGenerateColumns на true. Вам не нужно вызывать DataBind, это только для 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; }
    }
}
1 голос
/ 29 марта 2015

Вот еще одно решение, которому не нужно присваивать «имя» сетке данных, чтобы сетка данных могла быть элементом шаблона.

(в моем случае сетка данных - это элемент шаблона внутри TabControl.ContentTemplate)

Ключ для отображения нового столбца (добавляемого программно после первоначальной привязки) заставляет сетку данных обновляться. Из ответа в Принудительная регенерация WPF DataGrid Андрес предложил установить AutoGenerateColumns с false на true, чтобы обновить сетку данных.

Что означает, что мне просто нужно:

  1. Свяжите AutoGenerateColumns со свойством моего объекта
  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);
        }
 }

Надеюсь, эта помощь:)

1 голос
/ 29 января 2009

AutoGenerateColumns установлено в true? Если вы вносите изменения после первоначальной привязки, вам также придется вызывать DataBind () для повторной привязки измененного источника данных. Я знаю, что это верно для обратного вызова AJAX, я думаю это верно для элемента управления WinForms PostBack.

0 голосов
/ 29 января 2009

У меня была такая же проблема, и я выпустил 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
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...