我有一个从CSV文件填充的DataTable,然后使用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
。初始列是以编程方式生成的,因此不应该出现,因为设计器代码也继续生成最初用于调试的“设计”列。
道德:检查自动生成的代码!
答案 0 :(得分:2)
这听起来不对。为了测试它,我编写了一个简单的应用程序,它创建了一个DataTable并向其添加了一些数据
在button1.Click
上,它将表绑定到DataGridView
然后,我添加了第二个按钮,单击该按钮时,会向基础DataTable添加另一列
当我测试它时,我点击了第二个按钮,网格immedialtey反映了更新。
为了测试反向,我添加了第三个按钮,弹出一个带有DataGridView的对话框,该对话框绑定到同一个DataTable。在运行时,我然后向第一个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; }
}
}
答案 1 :(得分:1)
AutoGenerateColumns是否设置为true?如果在初始绑定后进行更改,则还必须调用DataBind()来重新绑定更改的数据源。我知道这对于AJAX回调是正确的,我认为对于WinForms控件PostBack来说是真的。
答案 2 :(得分:1)
这是另一种解决方案,你不需要分配一个&#34;名称&#34;到数据网格,这样数据网格就可以成为模板元素。
(在我的例子中,数据网格是TabControl.ContentTemplate中的模板元素)
显示新列的键(在初始绑定后以编程方式添加)是强制数据网格刷新。
根据{{3}}中的答案,Andres建议将AutoGenerateColumns
从false设置为true将强制数据网格刷新。
这意味着我只需要:
AutoGenerateColumns
绑定到我的对象的属性以下是代码:
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);
}
}
希望这有帮助:)
答案 3 :(得分:-1)
我有同样的问题,我发布了一个DataBind()。它不是万能的灵丹妙药,但它在一些情况下帮助了我。在EditItemIndex语句之后的EditCommand和UpdateCommand事件之后,我必须通过DataView捕获信息之前将其放入,
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
}