I have problem with creating listview. I am new in C# and wpf too.
I have tried different methods of filling ListView items and I can not solve it, because the input array is NxN dimensions. I found instructions on Bindig but I can not apply them because I can not create an object of that type, because the input array is dynamic.
I can fill header columns but no rows and columns with values. This code works but all values are together in one column.
public void PrintListView(ResultsTable results)
{
System.Windows.Controls.GridView gv = new System.Windows.Controls.GridView();
gv.AllowsColumnReorder = true;
int j=0;
foreach (DataColumn dc in results.Columns)
{
GridViewColumn gvCol = new GridViewColumn();
gvCol.Header = results.Columns[j].ColumnName;
gvCol.Width = 200;
gv.Columns.Add(gvCol);
j++;
}
lbVysledky.View = gv;
foreach (DataRow dr in results.Rows)
{
string[] array1 = new string[1000];
// List<string> zoznam = new List<string>();
// ObservableCollection<string> kolekcia = new ObservableCollection<string>();
int i = 0;
foreach (DataColumn dc in results.Columns)
{
array1[i] = dr[dc].ToString();
// zoznam.Add (dr[dc].ToString());
// kolekcia.Add(dr[dc].ToString());
i++;
}
this.lbVysledky.Items.Add(new ListViewItem { Content = pole[0] + pole[1]});
}
}
Can someone help me? Thanks
It looks like you're trying to populate the ListView by adding rows and columns one at a time. This is not the approach to use when populating a ListView. Instead, you add the ItemsSource (in this case, your results object) and tell the ListView what the DisplayMemberBinding is for each column, and it will display the proper values in each column for each row.
It probably just means modifying your loop where you add columns to the ListView to something like this:
foreach (DataColumn dc in results.Columns)
{
GridViewColumn gvCol = new GridViewColumn();
gvCol.DisplayMemberBinding = new Binding(dc.ColumnName);
gvCol.Header = results.Columns[j].ColumnName;
gvCol.Width = 200;
gv.Columns.Add(gvCol);
j++;
}
lbVysledky.View = gv;
Then just set the ItemsSource of the ListView to your results object like this:
lbVysledky.ItemsSource = results;
Also, as a side note, you don's appear to be using the foreach construct correctly. you're enumerating over each column, but you're keeping your own counter and accessing the column like this:
gvCol.Header = results.Columns[j].ColumnName;
In a foreach loop, you're already enumerating the columns with the dc variable, so you can access the column like this:
gvCol.Header = dc.ColumnName;
and you don't need to manually count the columns (with j).
Related
I have a datagridview with values that I add manualy with a datasource, however I want to add a button where the user can shuffle the order of where the values are located in the datagridview. Does anyone have an idead on how to apply this?
if it comes from sql statement with
SELECT * FROM table
ORDER BY NEWID()
but if it is a different form of datasource
var data = //un randomed data
var randomData = data.OrderBy(x => Guid.NewGuid()).ToList();
//then bind randomData to your datasource
so on button click, update it by
getData(){
//use either sql statement or OrderBy() then bind
}
Add a hidden column that contains a random number and sort the rows using that.
If you set AutoGenerateColumns to false you can specify the order of the columns.
void ShuffleDataGridView(DataGridView dataGridView, DataTable dataTable)
{
// add or update random sort order column
const string randomSortConst = "RandomSort";
if (!dataTable.Columns.Contains(randomSortConst))
{
dataTable.Columns.Add(randomSortConst, typeof(int));
}
var rand = new Random();
foreach (DataRow drw in dataTable.Rows)
{
drw[randomSortConst] = rand.Next();
}
// randomize column display
dataGridView.AutoGenerateColumns = false;
dataGridView.AllowUserToOrderColumns = false;
dataGridView.Columns.Clear();
var columnsToAdd = new List<DataColumn>();
foreach (DataColumn dcl in dataTable.Columns)
{
if (!(dcl.ColumnName == randomSortConst))
{
columnsToAdd.Add(dcl);
}
}
while (columnsToAdd.Count > 0)
{
var j = rand.Next(0, columnsToAdd.Count - 1);
var dgvtbc = new DataGridViewTextBoxColumn
{
DataPropertyName = columnsToAdd[j].ColumnName,
HeaderText = columnsToAdd[j].ColumnName // remove this line to hide column headings
};
dataGridView.Columns.Add(dgvtbc);
columnsToAdd.RemoveAt(j);
}
// sort the rows using the hidden random column
dataGridView.DataSource = new DataView(dataTable, string.Empty, randomSortConst, DataViewRowState.CurrentRows);
}
What's the equivalent in .NET to convert my DataGrid to a DataTable (DataGrid.ItemsSource isn't defined in .Net csharp.
Thanks!
DataTable dt = new DataTable();
dt = ((DataView)DataGrid1.ItemsSource).ToTable();
EDIT
This isn't a duplicate since the previous code is for WPF and I'm looking for an asp.net mvc csharp answer.
The ItemsSource is for WPF. Use the DataSource and cast it to DataTable like this:
dt = (DataTable)DataGrid1.DataSource;
EDIT: And if you get into trouble with above approach, you can use a custom method like this:
private DataTable ToDataTable(DataGridView dataGridView)
{
var dt = new DataTable();
foreach (DataGridViewColumn dataGridViewColumn in dataGridView.Columns)
{
if (dataGridViewColumn.Visible)
{
dt.Columns.Add();
}
}
var cell = new object[dataGridView.Columns.Count];
foreach (DataGridViewRow dataGridViewRow in dataGridView.Rows)
{
for (int i = 0; i < dataGridViewRow.Cells.Count; i++)
{
cell[i] = dataGridViewRow.Cells[i].Value;
}
dt.Rows.Add(cell);
}
return dt;
}
And then use it:
var dataTable = ToDataTable(dataGridView1);
Also MoreLinq is a good choice in case the type of Datasource is a list. Check this solution to know how to use it: https://stackoverflow.com/a/42550827/2946329
If you are referring to the System.Windows.Forms.DataGrid or System.Web.UI.WebControls.DataGrid, then the best way would be to cast the Datasource property to a DataTable.
Of course the Datasource property has to actually be a DataTable underlying type to begin with. You need to know the underlying type of the object stored in the Datasource property.
If the underlying type of Datasource is a generic list, then this SO post should help: How to convert a list into data table
FYI - The Windows Forms DataGrid control, according to Microsoft, has been replaced by the DataGridView.
if there is visible columns in datagridview you can use
private DataTable ToDataTable(DataGridView dataGridView)
{
var dt = new DataTable();
int columnCount = 0;
List<int> columnNumbers= new List<int>();
foreach (DataGridViewColumn dataGridViewColumn in dataGridView.Columns)
{
if (dataGridViewColumn.Visible)
{
dt.Columns.Add(dataGridViewColumn.Name);
columnNumbers.Add(columnCount);
}
columnCount++;
}
var cell = new object[columnNumbers.Count];
foreach (DataGridViewRow dataGridViewRow in dataGridView.Rows)
{
int i = 0;
foreach (int a in columnNumbers)
{
cell[i] = dataGridViewRow.Cells[a].Value;
i++;
}
dt.Rows.Add(cell);
}
return dt;
}
The custom method does not take into account the hidden columns. You are getting an error, because you have too many cells for the columns copied.
You can use :
int dgv1RowCount = dgv1.Rows.Count;
int numOfColumns = dgv1.Columns.GetColumnCount(DataGridViewElementStates.Visible) ;
int numCells = dgv1RowCount * numOfColumns;
// use numCells in the for loop
for (int i = 0; i < numOfCells ; i++)
{
enter code here
}
I am using telerik radgrid. I am binding the grid programatically. The grid loads correctly but the Nested grid loads multiple times.(the number of times the number of columns in nested grid). Below is my code
GridTableView tableViewOrders = new GridTableView(grid);
foreach (Application app in isParentApp)
{
DataTable tbl = new DataTable("nestedTable_" + app.AppId);
objGridList = GetGridList(app.AppId);
foreach (var nestedRow in objGridList)
{
GridRelationFields relationFields = new GridRelationFields();
relationFields.MasterKeyField = "AppId";
relationFields.DetailKeyField = "AppId";
tableViewOrders.ParentTableRelation.Add(relationFields);
GridBoundColumn boundColumn = new GridBoundColumn();
boundColumn.DataField = nestedRow.ColName;
boundColumn.HeaderText = nestedRow.ColName;
tableViewOrders.Columns.Add(boundColumn);
grid.MasterTableView.DetailTables.Add(tableViewOrders);
tbl.Columns.Add(nestedRow.ColName);
}
foreach(var rows in totalRows)
{
DataRow nestedDtRow = tbl.NewRow();
nestedDtRow["AppId"] = app.AppId;
foreach (var nestedRecord in nestedRecords)
{
nestedDtRow[nestedRecord.colName] = nestedRecord.Data;
}
tbl.Rows.Add(nestedDtRow);
}
tableViewOrders.DataSource = tbl;
}
While debugging "tbl" had only one table but the output displayed multiple tables.
`
You are Adding the columns over and over for each row in this loop:
foreach (var nestedRow in objGridList)
{
}
You only need to do this once outside the loop. See this answer on how to do add the columns outside the loop.
I have been able to make one existing column combo box column in the datagridview, how do I do it for several columns? Also how do I add existing distinct records in the combobox items? The user will be able to either choose value from combobox item or write their own. So far my code is:
dgvLoadTable.DataSource = null;
var context = new CadAdminEntities();
var TableName = cboSelectTable.Text.ToString();
var rawData = context.GetType().GetProperty(TableName).GetValue(context, null);
var truncatedData = ((IQueryable<object>)rawData).Take(0);
var source = new BindingSource { DataSource = truncatedData };
dgvLoadTable.DataSource = source;
dgvLoadTable.ReadOnly = false;
dgvLoadTable.AllowUserToAddRows = true;
DataGridViewComboBoxCell dgvCol = new DataGridViewComboBoxCell();
for (int row= 0; row < dgvLoadTable.Rows.Count; row++)
{
for (int col = 0; col < dgvLoadTable.Columns.Count; col++)
{
if(col==2||col==4)
this.dgvLoadTable[col,row] = dgvCol;
//This part throws error, as there is only one combobox
}
}
dgvLoadTable.Refresh();
This is easy to fix:
this.dgvLoadTable[col, row] = new DataGridViewComboBoxCell();
will create a fresh ComboBoxCell for each case.
You can delete the line
DataGridViewComboBoxCell dgvCol = new DataGridViewComboBoxCell();
Note that since you have a Databound DGV and the Columns were probably created automatically, you should keep in mind, that often one needs to switch off that automatism and create all column manually before setting the DataSource..
Here is my code:
DataSet data = new DataSet();
data.ReadXml("data.xml");
DataGridView grid = new DataGridView();
var genreCboBoxItems = data.Tables[0].AsEnumerable().Select(genre => genre.Field<string>("genre")).Distinct().ToArray();
// TODO: Make is so the 'genre' column in grid is a combo box?
grid.DataSource = data.Tables[0];
grid.Dock = DockStyle.Fill;
this.Controls.Add(grid);
*edit: genreCboBoxItems
Try this: (not tested)
var column = new DataGridViewComboBoxColumn();
column.DataSource = data.Tables[0].AsEnumerable().
Select(genre => new { genre = genre.Field<string>("genre") }).Distinct();
column.DataPropertyName = "genre";
column.DisplayMember = "genre";
column.ValueMember = "genre";
grid.DataSource = data.Tables[0];
// Instead of the below line, You could use grid.Columns["genre"].Visible = false;
grid.Columns.Remove("genre");
grid.Columns.Add(column);
This might help you cast DataGridViewColumn to DataGridViewComboBox.
First create DataGridViewComboBoxColumn using designer with proper name. Then say you have a list of String list and other string values to bind to that datagridview then use this code:
Below code will bind a list to two DataGridViewTextBoxCell and a DataGridViewComboBoxCell. Note AllCriterias is a list with two string values and a list of string. DGVEligibilityCriteria is the grid name.
for (int i = 0; i < AllCriterias.Count; i++)
{
DataGridViewTextBoxCell Cmb1 = (DataGridViewTextBoxCell)DGVEligibilityCriteria.Rows[i].Cells[0];
Cmb1.Value = AllCriterias[i].Name;
DataGridViewTextBoxCell Cmb2 = (DataGridViewTextBoxCell)DGVEligibilityCriteria.Rows[i].Cells[1];
Cmb2.Value = AllCriterias[i].Type;
DataGridViewComboBoxCell Cmb = (DataGridViewComboBoxCell)DGVEligibilityCriteria.Rows[i].Cells[2];
foreach (var filtervalue in AllCriterias[i].FilterValues)
{
Cmb.Items.Add(filtervalue);
}
}
Need to display the fist index as default by setting selectindex property.
Use this code : Here "filterValues" is the name of the DataGridViewComboBoxCell which u created in the datagridview designer.
foreach (DataGridViewRow row in DGVEligibilityCriteria.Rows)
{
row.Cells["filterValues"].Value = (row.Cells["filterValues"] as DataGridViewComboBoxCell).Items[0];
}