DataGrid: Dyanmically adding rows - c#

I am new to windows application. I need to add rows in the DataGrid dynamically which has person data. when i do the following is see only the last person in the last row. i see rows populating but with no data. If i do a break on the first fetch i do get the right one. But something is wrong. Any ideas
foreach (var p in personList)
{
gvAdminSummary.Rows.Add(new DataGridViewRow());
gvAdminSummary.Rows[gvAdminSummary.Rows.Count-1].Cells[0].Value = p.FName;
gvAdminSummary.Rows[gvAdminSummary.Rows.Count - 1].Cells[1].Value = p.LName;
gvAdminSummary.Rows[gvAdminSummary.Rows.Count - 1].Cells[2].Value = p.PNo;
}

The DataGridRowView.Add method accepts string arrays:
gvAdminSummary.Rows.Add( { p.FName, p.LName, p.PNo });
Likely, though, there's a better solution for you in binding the grid directly to your person list.

This may not be the right approach. Create a BindingSource and bind a collection of your objects to it. Then bind the BindingSource to the Grid's data source. Make sure your objects implement INotifyPropertyChanged. This way, whenever, you add an object to the collection, or change a property within your object, it'll automatically reflect in the grid.

I don't know about DataGridView, but if you want to stick to inserting data into the control directly, why not use ListView instead? It has an API more suited to your current needs or way of doing things.

Either
gvAdminSummary.Datasource = persons;
gvAdminSummary.databind();
Or
foreach (var p in personList)
{
DataGridViewRow dr = new DataGridViewRow();
dr.cells.add(new datagridcell()) etc.. populate cells
gvAdminSummary.Rows.add(dr);
}

Related

WPF DataGrid editable cells with Items put directively

So, I have a DataGrid, that I want to manipulate programmatically a lot.
string[] values = new string[something.Count];
for (int i = 0; i < somethingElse.Count; i++)
{
if (condition)
values[i] = Data[i].ToString();
else
values[i] = "";
}
var style = new System.Windows.Style(typeof(DataGridRowHeader));
style.Setters.Add(new Setter(DataGridRowHeader.ContentProperty, Data[0].ToString()));
MyGrid.Items.Add(new DataGridRow()
{
HeaderStyle = style,
Item = values
});
This I do in a loop and I am able to fill in my grid with all the data I need.
Later, I am able to access cells, edit them, take their values, whatever I want and need.
However, when user wants to use the grid as you would in MS Excel, the cells are not editable.
So I went the other way and created a :
ObservableCollection<ObservableCollection<string>> gridData = new ObservableCollection<ObservableCollection<string>>();
//*** ... *** the gridData is filled in the same way, you can imagine
MyGrid.ItemsSource = gridData;
This does fill in the data perfectly the same way, more than that, the data are now editable.
But my custom row headers disappeared.
I need them, also, I do not think I want to use binding for row header values.
Can the first approach be somehow modified to still be editable, but rows with data being filled the very same way?
I eventually solved this combining both the abovementioned approaches.
First, I generate ObservableCollection<ObservableCollection<string>> dataCollection, fill it with data.
Next I generate an ObservableCollection<DataGridRow> rowCollection collection.
In my declarative part of the loop from the first approach, that you can see in the question, I do this
rowCollection.Add(new DataGridRow()
{
HeaderStyle = style,
Item = dataCollection[i] //for the corresponding iteration element
});
This all ends up when setting
MyGrid.ItemsSource = rowCollection;
Till now (very little time of testing), this seems to be what I was looking for, hope it might help someone else aswell.

Updating item property in ListView

I am trying to figure out how to update a Object's property in a ListView after render. For an example, let's say that the ListView is DataBound to a collection of Employees. Each row displays the information of the employee. After the table is loaded, I needed to say "If an employee name = [RON] then change it to text [RONALD]".
I currently was thinking I could foreach the ListViewDataItems in the ListView, and go from there, but am stuck. Any help would be appreciated.
foreach(ListViewDataItem entry in lvProjectModeratorEntries.Items)
{
//I need to find the div where the firsName is
//displayed, and run my logic to update it.
}
I also thought I would get it through entry.DataItem but am stuck at that point.
It sounds like you could use the INotifyPropertyChanged Interface on your Employee model. In your listview item template, bind the text to the Employee's property that you wish to display. Then you can change your Employee objects.
to find each item in a Listview you can loop like this
for (int i = 0; i < lvProjectModeratorEntries.Items.Count; i++)
{
int ii = 1;
MessageBox.Show(lvProjectModeratorEntries.Items[i].SubItems[ii].Text);
ii++;
}
Using your own code:
foreach (ListViewItem item in lvTest.Items)
{
if (item.Text == "John")
item.Text = "John is gone";
}
That should give you a start on how to do things, yet I don't recommend it. There are more elegant and code-sustainable solutions. Have you thought about binding the listview to a List and make all the necessary business logic in the List, instead of the actual view?

Implementing Search functionality on a datagrid column in C# windows appl

I am working on a windows application using .net 2.0. The UI appl has a datagrid and the data will be populated from the XML file.
The data grid has more than 500 rows. Sorting functionality has implemented. but customer still wants a find option or a search functionality on one of the columns with a text box where user is going to enter first 3 letters and it has to search in the grid and has to show the related rows that starts with the give search criteria.
Any suggestions pls how to implement this....
Thanks
You can use a Filter option in the BindingSource object.
private BindingSource dashBoardBindingSource = new BindingSource();
dashBoardBindingSource.DataSource=<<data source items>>;
dashBoardBindingSource.Filter="Column Name=textbox.text";
datagrid.DataSource = dashBoardBindingSource;
Store off your full collection of data, and then when the filter needs to be performed, create the filtered collection and bind the filtered collection to the grid. Just wire up appropriate text changed events to your filter box, calling FilterGridData. It works nicely when filtering via multi-column as well. Oh, and you don't have to use BindingList here. Use whatever data source you want to bind to the grid - the core of this is just "create the filtered collection by filtering with LINQ."
BindingList<Foo> _allFoos;
private void LoadData(IEnumerable<Foo> dataToDisplayInGrid)
{
this._allFoos = new BindingList<Foo>(dataToDisplayInGrid.ToList());
this.FilterGridData(string.Empty);
}
private void FilterGridData(string filterText)
{
BindingList<Foo> filteredList = null;
if (!string.IsNullOrEmpty(filterText))
{
string lowerCaseFilterText = filterText.ToLower();
IList<Foo> filteredItems = this._allFoos.Where(x => (x.Name ?? string.Empty).ToLower().Contains(lowerCaseFilterText)).ToList();
filteredList = new BindingList<Foo>(filteredItems);
}
else
{
filteredList = new BindingList<Foo>(this._allFoos);
}
dataGrid.DataSource = filteredList;
}

DataGridView get current selected object

I need to get the currently selected object from da databound DataGridView.
I do not need the object of the current selected cell, but the object on which the whole row is based, in this case a BusinessObject whos properties make the columns of the grid.
I could go over the DataSource, but that itself is just an object and can be a BindingSource or a IBindingList or something like that - so not easy standartized way to get the wanted object.
Behind that is the need to just check the businessObject for a property called IsChanged and ask the user to save or discard the changes, before the bindingsource selects the next item. Therefore I must find out the current object inside RowValidating-Event of the DataGridView, since the BindingSource does not offer an event to stop changing before change occurs.See here for the well known problem
Thanks for reading ;-)
DataGridViewRow.DataBoundItem contains the 'business' object it is bound to.
Here is my code put this into your Person class
public static explicit operator Person(DataRow dr)
{
Person p = new Person();
p.adi = dr.ItemArray[0].ToString();
p.id = Int32.Parse(dr.ItemArray[1].ToString());
p.soyadi = dr.ItemArray[2].ToString();
p.kartNo = dr.ItemArray[3].ToString();
p.dogumTarihi = DateTime.Parse( dr.ItemArray[4].ToString() );
p.adres = dr.ItemArray[5].ToString();
p.meslek = dr.ItemArray[6].ToString();
p.telefon = dr.ItemArray[7].ToString();
p.gsm = dr.ItemArray[8].ToString();
p.eposta = dr.ItemArray[9].ToString();
return p;
}
and this is a update button click
DataRow row = (dataGridView1.SelectedRows[0].DataBoundItem as DataRowView).Row;
Person selected = (Person)row;
You can also use this short code.
Person selected = dataGridView1.SelectedRows[0].DataBoundItem as Person;
What about this way?
foreach (DataGridViewRow item in this.dataGridView1.SelectedRows)
{
MessageBox.Show(item.Cells[0].Value.ToString());
}
We can get multiple selected rows data.
Since you did state the IBindingList - yes as others have said the DataBoundItem property will give you what you need - there is an issue with it that I had experienced previously and ended up with a null reference but right now I can not think of the scenario in which it happened.
If you are databound using a BindingSource - you can capture the CurrentChanged, CurrentItemChanged events of your BindingSource , then you need not have an additional IsChanged Property on your B.O. .. , also the underlying datasource could also indicate modified - for example if you have BindingSource bound to a datatable the row would give you a modified flag.
You can get the selected cell value like this
yourDGV.CurrentCell.Value;
If you want the value in the form of a String just use ToString() method like this
yourDGV.CurrentCell.Value.ToString();
This should do it

Adding an item to a bound WPF ListBox

Ok, this has been a head scratcher for me. I have a ListBox I am binding to a linq query like so:
private IQueryable<Feed> _feeds;
public IQueryable<Feed> Feeds
{
get
{
if (_feeds == null)
{
var feedsQuery = from f in _db.Feed orderby f.Title select f;
_feeds = feedsQuery;
}
return _feeds;
}
}
public Options()
{
InitializeComponent();
this.DataContext = Feeds;
}
(For the record I've also tried List, instead of IQueryable)
Everything shows up great and I have a databound form that allows you to edit a record and all of those changes work just fine, the modified data shows up in the list.
The problem comes with I add an item. Nothing shows up in the list. The data goes into the database fine, but the only way to see the data is closing and restarting my app. I'm using the code below as an example:
Feed feed = new Feed()
{
ID = Guid.NewGuid(),
Url = "http://www.test.com",
Title = "Test"
};
_db.Feed.InsertOnSubmit(feed);
_db.SubmitChanges();
_db.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues);
(with or without the _db.Refresh nothing happens)
What's going on?
You are doing everything right, you jus need to use ObservableCollection. This will notify the ListBox about any changes in the list and refresh it automatically.
From MSDN
In many cases the data that you work
with is a collection of objects. For
example, a common scenario in data
binding is to use an ItemsControl
such as a ListBox, ListView, or
TreeView to display a collection of
records.
P.S. you don't need a db refresh
Unless notified otherwise, the ListBox only iterates once over its ItemsSource. Your query is only being run once.
The query object doesn't know when the database changes (and Refresh doesn't help; see below)--it's up to you to know (or anticipate) that and to rerun relevant queries at the appropriate times.
Stan R mentions ObservableCollection. That's fine, but simply storing the result of your query in an ObservableCollection won't solve the problem unless you do some work to update the collection yourself when the database changes. This means rerunning the query and manually adding new items and removing deleted items from the collection. (You could alternatively just rerun the query and set the entire result back in to the ListBox, but that means a whole new set of items will be created--not very performant, and maybe not what you want for other reasons.)
As an aside, your call to DataContext.Refresh is probably not doing what you think it is. From the docs:
This method is useful after an optimistic concurrency error to bring items into a state for another attempt. It updates the state of the primitive fields and properties on the objects.
Okay. I'm not positive this is 100% the correct way to use the ObservableCollection, but this seems to work:
private ObservableCollection<Feed> _feeds;
public ObservableCollection<Feed> Feeds
{
get
{
if (_feeds == null)
{
var feedsQuery = from f in _db.Feed orderby f.Title select f;
_feeds = new ObservableCollection<Feed>();
foreach (var item in feedsQuery)
{
_feeds.Add(item);
}
}
return _feeds;
}
}
And add my item:
Feed feed = new Feed()
{
ID = Guid.NewGuid(),
Url = "http://www.test.com",
Title = "Test"
};
_db.Feed.InsertOnSubmit(feed);
_db.SubmitChanges();
// manually update the list
Feeds.Add(feed);
It took me a little while to figure out I had to update the list manually (thanks Ben), but it all seems to work. Sorting would be nice, but I'll worry about that another time.

Categories

Resources