Hi all,I am currently facing a strange problem with the WinGrid.It is a standard WinGrid, bound to an object datasource (List<item>).I added an UnboundColumn to display a "light" icon that indicates its status (red, green).On InitializeRow the calculation is done and a predefined (for reuse) Appearance is assigned to the cell (unbound column).Now imagine the following rows (Id, IndicatorImage):1 green2 green3 red4 red
now if I remove the data entry from the datasource that contains Id = 2 I assumed to have the following rows:1 green3 red4 red
Unfortunately I get this:1 green3 green4 red
It seems that the indicator image stays the same for the rows (the bottom one is removed though)
Any hint is kindly appreciated,best regardsAndy
Hi Andy,
Can you post your InitializeRow code so I can see what it's doing? It seems to me that, since the color on the existing row is changed, the InitializeRow must be firing for that row and the InitializeRow code must therefore be applying the wrong Appearance to the row.
Also, what version of the grid are you using? It's also possible that this is a bug in a very old version of the grid where it's re-using the UIElements incorrectly. But that bug was fixed many years ago.
Hi Mike,
good hearing from you, I hope you are doing fine.
Here is the InitializeRow code:
void grdBalance_InitializeRow(object sender, InitializeRowEventArgs e) { if (e.Row.GetType() == typeof(UltraGridRow)) { // checking flag-state ParsedBalanceStorageListEntry entry = e.Row.ListObject as ParsedBalanceStorageListEntry; int count = GetCountFromItem(entry); if (count == 0) { e.Row.Cells[TrafficLightColumnKey].Appearance = RedMarkerAppearance; return; } if (count == 1) { e.Row.Cells[TrafficLightColumnKey].Appearance = GreenMarkerAppearance; return; } e.Row.Cells[TrafficLightColumnKey].Appearance = YellowMarkerAppearance; return; } }
...and the stuff related to the appearances I use:
private Appearance _greenMarkerAppearance; private Appearance GreenMarkerAppearance { get { if (_greenMarkerAppearance == null) { _greenMarkerAppearance = GetDefaultTrafficLightAppearance("GreenMarkerAppearance"); _greenMarkerAppearance.Image = GlobalResources.Images.Misc.Flags.NonCountryFlags.NonCountryFlagsImageProvider.FlagGreen.ResizeTo(new Size(16, 16)); } return _greenMarkerAppearance; } } private Appearance _redMarkerAppearance; private Appearance RedMarkerAppearance { get { if (_redMarkerAppearance == null) { _redMarkerAppearance = GetDefaultTrafficLightAppearance("RedMarkerAppearance"); _redMarkerAppearance.Image = GlobalResources.Images.Misc.Flags.NonCountryFlags.NonCountryFlagsImageProvider.FlagRed.ResizeTo(new Size(16, 16)); } return _redMarkerAppearance; } } private static Appearance GetDefaultTrafficLightAppearance(string key) { Appearance appearance = new Appearance(key); appearance.ImageHAlign = HAlign.Center; appearance.ImageVAlign = VAlign.Top; return appearance; }
I use this to meet the guidelines I read about in your UltraGrid Tuning-Tips article for reusing appearances.
We are currently using version 11.2.20112.1010, so I assume that is already a version where the mentioned bug was fixed ;)
Let me know if you need any further information.
Best regards and have a great dayAndy
Okay, I'm glad it's working, now. That seems to confirm my suspicion that this is some kind of timing issue.
What is GetCountFromItem doing? I'm guessing that maybe this method is not just accessing fields directly on the row's ListObject, but is also accessing child rows or some other related rows and those rows haven't been updated at the time the InitializeRow event fires.
the GetCountFromItem function is actually accessing the ListObject of the row, reads one property and then checks the database for related information.So it is not directly accessing child nodes. What it does is to use Entity Framework to check the information necessary for the "count" context.paymentsDue.Count(w => w.BookingId == entry.BookingId) where entry is the casted ListObject
Anyway, it still might be a timing issue as you mentioned, because currently it initializes one entity context per call to InitializeRow, which is of course not perfect.Here is where the buffering should come into account, but I am still working on it.
When this part of the application is optimized I can easily uncomment the solution you had to fix this and see if it still works... and of course let you know about the outcome if you are interested. This will all happen within this week, so everything will be fresh in my mind ;)
CheersAndy
Yes, I see from the code here that you are passing the ListObject into the GetCountFromItem method. It looks to me like the ListObject of the row is correct - it has to be or the grid would not be showing the correct value in the first column. But GetCountFromItem must be accessing data from the data source that hasn't caught up to the delete operation, yet.
I am not quite sure if I get this correctly.
The GetCountFromItem uses a different datasource that the grid.
The grid is actually bound to a List<item> that is disconnected from the database.So removing the item from the List<item> via a call to the Lists "_list.Remove(item)" function just removes the item and does not involve any database operations at this point.
Funny was that the order of the IndicatorImage stays the same if you look at it from the top. So if I removed an item from the middle the IndicatorImages stay the same from the top. It looks like that all rows after the deleted one just move one up and the bottom one is removed completely, leaving the order of indicator images intact...
Like if you just empty the row of the deleted item (only the cells that do not show the image). Then move all lower entries (only cells without image) one up which results in the bottom row only containing the image and empty cells. Then remove the bottom row...
I am going to do a test tomorrow with a simple structure and check if this is happening there too. I will send you the project if it turns out to behave the same, would that be ok? If it doesn't behave like this the problem is in my structure.
cheersAndy
Sure, if it looks like this is a problem with the grid, then please post a sample duplicating the issue and we will be happy to check it out.
Yeah, that's pretty much what I thought. There has to be something in GetCountFromItem that is getting the wrong data at that particular point in time.
Hi Mike,I made a sample to see if it is related to the grid, but I wasn't able to reproduce it.Even without updating the grid and refreshing the rows it works fine, it takes a while but it works fine...
If you are interested I can send you the sample.
Anyway, your solution for fixing the problem works fine and I'll stick to it. Adding buffers was easy, so it performs pretty fast now.
Thanks a lot for your help Mike, I really appreciate your great support!
have a great time,cheersAndy