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.
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);
}
I have a datatable running in a foreach loop, getting site usage information on multiple sahrepoint websites. I would like to be able to add a column next to each foreach iteration adding the site url, I can only figure out how to do this adding a new row making the site url appear below the entry. Like So:
How can I get the url to go into the row above it?
My code is below:
SPListItemCollection items = list.GetItems(query);
DataTable aggregatedTable = new DataTable();
foreach (SPListItem item in items)
{
string url = item["SiteUrl"].ToString();
try
{
using (SPSite siteadd = new SPSite(url))
using (SPWeb webadd = siteadd.OpenWeb())
{
//
DataTable table = webadd.GetUsageData(Microsoft.SharePoint.Administration.SPUsageReportType.browser, Microsoft.SharePoint.Administration.SPUsagePeriodType.lastMonth);
table.Columns.Add("url");
if (table == null)
{
// HttpContext.Current.Response.Write("Table Null");
}
else
{
DataRow dr;
dr = table.NewRow();
dr["url"] = url;
table.Rows.Add(dr);
// table.Rows.Add(url);
aggregatedTable.Merge(table);//Append the data to previous site data.
}
}
}
catch { }
}
dataGridView1.DataSource = aggregatedTable;//bind datatable with
Why you adding a new row to you existing DataTable rather you should set value to you existing row.
e.g.
var CurRow = table.AsEnumerable().FirstOrDefault();
table.Columns.Add("url");
if (CurRow != null)
{
CurRow["url"] = url;
}
I am trying to learn how to join two data tables into one using Linq. My linq query is working correctly and I can see expected values in it. However, when I loop the linq results, and assign the values to a newly created data row and add that row to a new data table, the rows come out empty.
Here is my code:
private void btnCombine_Click(object sender, EventArgs e)
{
var innerJoinQuery =
from strRow in StrDataTable.AsEnumerable()
join intRow in IntDataTable.AsEnumerable()
on strRow.Field<int>("IntID") equals intRow.Field<int>("ID")
select new {
IntOne = intRow.Field<int>("FirstNum"),
IntTwo = intRow.Field<int>("SecondNum"),
StrOne = strRow.Field<string>("FirstStr"),
StrTwo = strRow.Field<string>("SecondStr"),
StrThree = strRow.Field<string>("SecondStr")
};
DataTable newTable = new DataTable();
newTable.Columns.Add("IntOne");
newTable.Columns.Add("IntTwo");
newTable.Columns.Add("FirstStr");
newTable.Columns.Add("SecondStr");
newTable.Columns.Add("ThirdStr");
newTable.Columns["IntOne"].DataType = System.Type.GetType("System.String");
newTable.Columns["IntTwo"].DataType = System.Type.GetType("System.String");
newTable.Columns["FirstStr"].DataType = System.Type.GetType("System.String");
newTable.Columns["SecondStr"].DataType = System.Type.GetType("System.String");
newTable.Columns["ThirdStr"].DataType = System.Type.GetType("System.String");
foreach (var row in innerJoinQuery)
{
DataRow rowToAdd = newTable.NewRow();
rowToAdd.ItemArray[0] = row.IntOne.ToString();
rowToAdd.ItemArray[1] = row.IntTwo.ToString();
rowToAdd.ItemArray[2] = row.StrOne.ToString();
rowToAdd.ItemArray[3] = row.StrTwo.ToString();
rowToAdd.ItemArray[4] = row.StrThree.ToString();
newTable.Rows.Add(rowToAdd);
}
dataGridView3.DataSource = newTable;
}
Using DataRow.ItemArray property with individual values doesn't work - instead, create the object[] array and then set the whole thing to the .ItemArray property. See this MSDN page for additional examples.
foreach (var row in innerJoinQuery)
{
DataRow rowToAdd = newTable.NewRow();
object[] items = new object[] {
row.IntOne.ToString(),
row.IntTwo.ToString(),
row.StrOne.ToString(),
row.StrTwo.ToString(),
row.StrThree.ToString()
};
rowToAdd.ItemArray = items;
newTable.Rows.Add(rowToAdd);
}
Alternately, use the DataRow indexer directly, which works with individual columns:
rowToAdd[0] = row.IntOne.ToString();
rowToAdd[1] = row.IntTwo.ToString();
rowToAdd[2] = row.StrOne.ToString();
rowToAdd[3] = row.StrTwo.ToString();
rowToAdd[4] = row.StrThree.ToString();
Additionally, when creating columns, there is a constructor that takes the type which can save you some code. Your first two column types are mismatched.
newTable.Columns.Add("IntOne", typeof(int));
newTable.Columns.Add("FirstStr", typeof(string));
The first two values appear to be Integers:
IntOne = intRow.Field<int>("FirstNum"),
IntTwo = intRow.Field<int>("SecondNum"),
But the DataType you assign the columns to is String:
newTable.Columns["IntOne"].DataType = System.Type.GetType("System.String");
newTable.Columns["IntTwo"].DataType = System.Type.GetType("System.String");
Update those to int's and see if that resolves it:
newTable.Columns["IntOne"].DataType = System.Type.GetType("System.Int32");
newTable.Columns["IntTwo"].DataType = System.Type.GetType("System.Int32");
rowToAdd.ItemArray[0] = row.IntOne;
rowToAdd.ItemArray[1] = row.IntTwo;
You may also need to supply the DataPropertyName for the columns:
newTable.Columns["IntOne"].DataPropertyName = "FirstNum";
newTable.Columns["IntTwo"].DataPropertyName = "SecondNum";
...
And ensure that the AutoGenerateColumns value is set to false
dataGridView3.AutoGenerateColumns = false;
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).
Would someone kindly assist me with the following? I have two DataGridView objects that each display a DataTable, where the two datatables are related with the following code:
DataSet dSet = new DataSet();
DataTable ParentList = ListToDataTable(_listOfAllAlbumObjects);
DataTable ChildList = ListToDataTable(_listOfAllTrackObjects);
dSet.Tables.AddRange(new DataTable[]{ParentList, ChildList});
DataColumn parentRelationColumn = ParentList.Columns["AlbumId"];
DataColumn childRelationColumn = ChildList.Columns["AlbumId"];
dSet.Relations.Add("ParentToChild", parentRelationColumn, childRelationColumn);
ParentDataGridView.DataSource = dSet;
ParentDataGridView.DataMember = "ParentList";
ChildDataGridView.DataSource = ???;
ChildDataGridView.DataMember = "ParentToChild";
Both DataTables are actually List<> converted to DataTables with the following:`
public static DataTable ListToDataTable<T>( IList<T> data)
{
var props = TypeDescriptor.GetProperties(typeof(T));
var table = new DataTable();
for (var i = 0; i < props.Count; i++)
{
PropertyDescriptor prop = props[i];
table.Columns.Add(prop.Name, prop.PropertyType);
}
var values = new object[props.Count];
foreach (T item in data)
{
for (int i = 0; i < values.Length; i++)
{ values[i] = props[i].GetValue(item); }
table.Rows.Add(values);
}
return table;
}
Initially it appears that the each DataGridView displays the data appropriately; however the child DataGridView does not update with any change of record in the parent DataGridView.
I see that the tables need to be interconnected through the binding-source; however I don't believe there is a true binding-source here.
Could someone please steer me in the right direction? Thanks.
There's an MSDN article showing what you want to do:
How to: Create a Master/Detail Form Using Two Windows Forms DataGridView Controls
Here's how this might work for you:
Either through the designer or through code add two BindingSources to your project: parentBindingSource and childBindingSource. Then try this in place of the code you have.
// Associate your BSs with your DGVs.
ParentDataGridView.DataSource = parentBindingSource;
ChildDataGridView.DataSource = childBindingSource;
// (Most of) your code here:
DataSet dSet = new DataSet();
DataTable ParentList = ListToDataTable(_listOfAllAlbumObjects);
DataTable ChildList = ListToDataTable(_listOfAllTrackObjects);
dSet.Tables.AddRange(new DataTable[]{ParentList, ChildList});
DataColumn parentRelationColumn = ParentList.Columns["AlbumId"];
DataColumn childRelationColumn = ChildList.Columns["AlbumId"];
dSet.Relations.Add("ParentToChild", parentRelationColumn, childRelationColumn);
// Let's name this DT to make clear what we're referencing later on.
ParentList.TableName = "ParentListDT";
// Rather than set the data properties on your DGVs, set them in your BindingSources.
parentBindingSource.DataSource = dSet;
parentBindingSource.DataMember = "ParentListDT";
childBindingSource.DataSource = parentBindingSource;
childBindingSource.DataMember = "ParentToChild";