Is there a way to get an iteratable collection of all the cells in a DataGrid regardless of whether they are selected or not
If you mean DataGridCells you could use Vincent Sibals helper functions to iterate over all rows DataGrid.Items and columns DataGrid.Columns.
public DataGridCell GetCell(int row, int column)
{
DataGridRow rowContainer = GetRow(row);
if (rowContainer != null)
{
DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(rowContainer);
// try to get the cell but it may possibly be virtualized
DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
if (cell == null)
{
// now try to bring into view and retreive the cell
DataGrid_Standard.ScrollIntoView(rowContainer, DataGrid_Standard.Columns[column]);
cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
}
return cell;
}
return null;
}
public DataGridRow GetRow(int index)
{
DataGridRow row = (DataGridRow)DataGrid_Standard.ItemContainerGenerator.ContainerFromIndex(index);
if (row == null)
{
// may be virtualized, bring into view and try again
DataGrid_Standard.ScrollIntoView(DataGrid_Standard.Items[index]);
row = (DataGridRow)DataGrid_Standard.ItemContainerGenerator.ContainerFromIndex(index);
}
return row;
}
Edit
If grid is your DataGrid you get a list of all DataGridCells like this:
List<DataGridCell> allCellList = new List<DataGridCell>();
for (int i = 0; i < grid.Items.Count; i++)
{
for (int j = 0; j < grid.Columns.Count; j++)
{
allCellList.Add(grid.GetCell(i, j));
}
}
For the sake of convenience (not necessarily performance), you can populate your data (including all cells from all column and rows) from your DataGrid to a single DataTable, which provides functions to help manipulate your data such as iteration, filtering, sorting etc.
// Populate a DataGrid to a DataTable
DataTable dt;
DataView dv = (DataView) myDataGrid.DataSource;
dt = dv.Table.DataSet.Tables[0];
You can subsequently convert any of a specific column to a collection or list using generics in as short as one line of code. See how-do-you-convert-a-datatable-into-a-generic-list:
List<DataRow> myList = dt.Rows.Cast<DataRow>().ToList();
It saves you from writing loops.
To fix the error thrown by the line...
DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>
(rowContainer);
Add this routine:
private T GetVisualChild<T>(DataGridRow rowContainer)
{
throw new NotImplementedException();
}
Related
I have a method SelectedRow() that grabs the content of a selected DataGrid row
private System.Data.DataRowView SelectedRow()
{
System.Data.DataRowView row = (System.Data.DataRowView)dgBrokerages.SelectedItems[0];
return row;
}
and would like to know how I can obtain an int containing the number of Columns that row contains.
private int NumColumns()
{
System.Data.DataRowView row = SelectedRow();
return row.Length; // <- Something like that
}
I'm basically looking for if there is a row.Length or row.Size?
Thanks,
iato
Try this:
private int NumColumns()
{
System.Data.DataRowView row = SelectedRow();
return row.Row.Table.Columns.Count;
}
I am working on WPF application which includes WPF chart. I am facing a situation.
I want to draw the chart only for values by ignoring blank values.
In application the data is contained by a datagrid and same data will be reflected in the graph, but datagrid having blank values(DBNull.Value).
So, I want to generate graph with only values by ignoring the blank values.
Here is my code for generating graph.
for (int col = 1; col < dtGeneric.Columns.Count; col++)
{
valueList = new List<KeyValuePair<string, double>>();
gLineSeries= new System.Windows.Controls.DataVisualization.Charting.LineSeries();
for (int row = 0; row < dtGeneric.Rows.Count - 1; row++)
{
if (string.IsNullOrEmpty(XaxisValue))
{
XaxisValue = "0";
}
YAxisValue = dtGeneric.Rows[row][col].ToString();
if (string.IsNullOrEmpty(YAxisValue))
{
YAxisValue = "0";
}
valueList.Add(new KeyValuePair<string, double>(XaxisValue, Convert.ToDouble(YAxisValue)));
}
gLineSeries.DependentValuePath = "Value";
gLineSeries.Style = gLineSeries.PolylineStyle;
gLineSeries.IndependentValuePath = "Key";
gLineSeries.ItemsSource = valueList;
gLineSeries.Title = dtGeneric.Columns[col].Caption.Replace('_', '.').ToString();
gLineSeries.AnimationSequence = AnimationSequence.FirstToLast;
chartControl.Series.Add(gLineSeries);
}
}
As you can see in the code, I have used keyvaluepair to draw the graph. So I am unable to add null value in the Value of keyvaluepair. I have tried with double.NaN but that is not working.
I have iterated all the columns because all the column will have its separate graph.
I have tried one logic to create the graph which is:
for (int col = 1; col < dtGeneric.Columns.Count; col++)
{
valueList = new List<KeyValuePair<string, double>>();
gPositionLineSeries = new System.Windows.Controls.DataVisualization.Charting.LineSeries();
for (int row = 0; row < dtGeneric.Rows.Count - 1; row++)
{
if (!string.IsNullOrEmpty(dtGeneric.Rows[row][0].ToString()) && !string.IsNullOrEmpty(dtGeneric.Rows[row][col].ToString())) //Null values will be ignored for graph generation...
{
XaxisValue = dtGeneric.Rows[row][0].ToString();
YAxisValue = dtGeneric.Rows[row][col].ToString();
valueList.Add(new KeyValuePair<string, double>(XaxisValue, Convert.ToDouble(YAxisValue)));
}
else
{
continue;
}
}
}
Above code is working fine but the X-axis values in the graph is not in order.
Please tell me some solution.
use below code in if block
string.IsNullOrEmpty(row.Cells[clm.Index].Value.ToString())
We have WPF application, In which we use DataGrid on one form.
At runtime, when we Enter value in DataTemplate column, I need to Show SUM of that specific column in DATAGRID Footer.
So when each time I change value in any Cell of That AMOUNT column, The correct SUM of that column need to be display.
Which event I should try.
I have tried this code , But it need to press tab each time, it does not display Correct SUM.
private void dgInfo_RowEditEnding(object sender, Microsoft.Windows.Controls.DataGridRowEditEndingEventArgs e)
{
Microsoft.Windows.Controls.DataGridRow row = this.dgInfo.ItemContainerGenerator.ContainerFromIndex(e.Row.GetIndex()) as Microsoft.Windows.Controls.DataGridRow;
ContentPresenter CP = dgInfo.Columns[3].GetCellContent(row) as ContentPresenter;
TextBlock t = FindVisualChild<TextBlock>(CP);
if (t != null && t.Text.Length > 0)
{
decimal d = Convert.ToDecimal(t.Text);
sum = sum + d;
txtTotal.Text = sum.ToString();
}
}
void dgInfo_CellEditEnding(object sender, Microsoft.Windows.Controls.DataGridCellEditEndingEventArgs e)
{
decimal tot = 0;
GetFaltyExpenseGridResult newRecord;
for (int i = 0; i < (dgInfo.Items.Count - 1); i++)
{
newRecord = (GetFaltyExpenseGridResult)((ContentPresenter)dgInfo.Columns[0].GetCellContent(dgInfo.Items[i])).Content;
if (newRecord != null)
{
decimal d = Convert.ToDecimal(newRecord.Amount);
tot = tot + d;
txtTotal.Text = tot.ToString();
}
}
}
Windows 7 (64 bit), .NET 4 (32 bit app)
I have a subclassed System.Windows.Forms.ListView comprising 2 columns displayed
in "Details" view. Only text fields are involved. The list comprises about 100
rows. On initial display all fields are drawn clearly but when scrolling or
"paging" with the scroll bar the text of some fields in the first column becomes
unreadable. It appears to be overwriten with random lines and blotches.
Is there anything that I can do to ensure that the text is clearly drawn in column 0?
The effect is diminished (clarity improved) when using remote desktop across a
LAN.
The effect disappears (all text is drawn clearly) when using remote desktop
across a WAN.
The ListView has always drawn perfectly on Windows XP.
For the purposes of a stripped down test, column header and DrawItem calls are ingored. The problem area is OnDrawSubItem which comprises the code
protected override void OnDrawSubItem(DrawListViewSubItemEventArgs e)
{
using (StringFormat sf = new StringFormat(StringFormatFlags.NoWrap))
{
Rectangle rect = new Rectangle(e.Bounds.Left
,e.Bounds.Top, e.Bounds.Width, e.Bounds.Height);
e.Graphics.DrawString(e.SubItem.Text, this.Font, Brushes.Black
,rect, sf);
}
base.OnDrawSubItem(e);
}
The following is the complete code that reproduces the problem:
using System;
using System.Windows.Forms;
using System.Drawing;
///
/// Build by saving to a file called LVTrial.cs and then executing "csc LVTrial.cs"
/// Scroll list up and down on a windows 7 box and the first column of text is corrupted.
///
class MyListView : ListView
{
Random randomiser = new Random();
private const int NUM_ROWS = 100;
private const int NUM_COLS = 2;
public MyListView()
{
this.Location = new System.Drawing.Point(23, 25);
this.OwnerDraw = true;
this.Size = new System.Drawing.Size(625, 387);
this.TabIndex = 0;
this.UseCompatibleStateImageBehavior = false;
this.View = System.Windows.Forms.View.Details;
for (int ii = 0; ii < NUM_COLS; ii++)
{
this.Columns.Add((
(System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())));
}
for (int ii = 0; ii < NUM_ROWS; ii++)
{
this.Items.Add( new ListViewItem(
new string[NUM_COLS] { CreateRandomString(1, 6), CreateRandomString(1, 6) } ) );
}
}
protected override void OnDrawSubItem(DrawListViewSubItemEventArgs e)
{
using (StringFormat sf = new StringFormat(StringFormatFlags.NoWrap))
{
Rectangle rect = new Rectangle(e.Bounds.Left
,e.Bounds.Top, e.Bounds.Width, e.Bounds.Height);
e.Graphics.DrawString(e.SubItem.Text, this.Font, Brushes.Black
,rect, sf);
}
base.OnDrawSubItem(e);
}
private string CreateRandomString(int minLength, int maxLength)
{
string str = string.Empty;
int length = randomiser.Next(minLength, maxLength + 1);
for (int ii = 0; ii < length; ii++)
{
int asciiChar = randomiser.Next(32, 126); // ascii range
str += Convert.ToChar(asciiChar);
}
return str;
}
}
class LVTrial : Form
{
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new LVTrial());
}
private LVTrial()
{
MyListView myListView = new MyListView();
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(674, 440);
this.Controls.Add(myListView);
this.Text = "LVTrial";
}
}
I have recorded this as a Windows 7 bug at https://connect.microsoft.com/VisualStudio/feedback/details/657909/subclassed-listview-column-0-displays-corrupted-text-on-windows-7
My own workaround for the problem was to insert an additional column at position 0. I now draw a rectangle with a transparent brush in column 0 for each item. All of which stops the text in the column to the right being drawn corrupt. I imagine drawing an image would achieve the same thing but I have not tried it. You can't hide this dummy column as the problem simply transfers to the second column (i.e. the first visible coolumn).
Another tip is that it seems to be performance related. The bug was more likely to occur with 100 items in the list view than 10,000.
Seems like this would be easy to do, but it appears its not so simple. I have a 2d array of floats or ints and I'd like to display it in a grid like control so it acts similar to Excel in regards to being able to move around with the arrow keys, tab keys, etc. The size of the array will vary. This comes close, but works well only for displaying:
How to populate a WPF grid based on a 2-dimensional array
I found the easiest way would be to use datatables and create one dynamically :
DataTable dt = new DataTable();
int nbColumns = 10;
int nbRows = 5;
for (int i = 0; i < nbColumns; i++)
{
dt.Columns.Add(i.ToString(), typeof(double));
}
for (int row = 0; row < nbRows; row++)
{
DataRow dr = dt.NewRow();
for (int col = 0; col < nbColumns; col++)
{
dr[col] = col;
}
dt.Rows.Add(dr);
}
myDataGrid.ItemsSource = dt.DefaultView;
Of course this is just a random table, you can load your 2d or Xd array in your DataTable. And also, you don't have to implement IEnumerable and stuff...