I am working on a page with two tables: one to show all the items, and one to show only the selected items. An item can added to/removed from the selected list by a checkbox in either table that is bound to a boolean in the view models. The view models notify other entities in the page that an item has been selected or deselected by way of a delegate that is passed in on construction of the view model:
public bool ItemViewModel.Selected { get { return this.selected; } set { if (this.itemSelectedChangedHandler != null && value != this.selected) { this.selected = value; this.itemSelectedChangedHandler(this.item, this.selected); } } }
When an item is selected/deselected, the selected list will update by hiding non-selected items and showing selected items. It will also call a method to set the selected value of the view model without invoking the itemSelectedChangedHandler:
private void PageViewModel.UpdateSelectedItemsTable() { foreach (var row in this.selectedItemsTable.Rows) { var itemViewModel = row.ListObject as ItemViewModel;
if (this.dataModule.SelectedItems.Contains(itemViewModel.Item)) { itemViewModel.Select(true); itemViewModel.UpdateChildren(); row.ExpandAll(); row.Hidden = false; } else { itemViewModel.Select(false); row.CollapseAll(); row.Hidden = true; } }
}
public void ItemViewModel.Select(bool selected) { if (this.selected != selected) { this.selected = selected; this.OnPropertyChanged(nameof(this.Selected)); } }
I can successfully select and deselect items from the table of all items (which has a different view model but ends up calling the same UpdateSelectedItemsTable), however, when I try to deselect an item from the selected table, I can deselect the first item, but subsequent items will not enter into their set accessors when I click their checkbox. To make debugging even more confusing, if I have a breakpoint on the set accessor from the beginning, before I select or deselect any items, I can successfully deselect all items by clicking their checkbox in the selected items table. I have no idea why the same code would have different outcomes when I step through it and when I don't.
Any thoughts or suggestions would be appreciated at this point!
Thank you!
Hello Tanner,
Your application’s logic is quite complex, and I am not able to reproduce it at my side. So can you please try to isolate this behavior in a small sample project and send it to me. This will allow me to investigate this behavior, and to try to find the root of this issue. Please let me know also, which the exact version of Infragistics for Windows Forms you are using is.
Looking forward to your reply and sample provided.
Hi Mike,
Thank you for the reply. I am trying to isolate this behavior in a small project, but it is eluding me. Based on the behavior, do you have any initial thoughts on what might be causing it? I was thinking that having a view model initiate a sequence to update its own properties might cause the binding to break, but it works in the isolated sample project, so I am still searching for the culprit. I think I have to take everything out of my main project and slowly add stuff in until it breaks.
Hi Tanner,
I'm not sure I am following all of that. But if you have a singleton class that is handling validation, then is it possible that when one checkbox is unchecked, it somehow causes the other checkbox's values to change, which causes all of them to validate, which then causes a cascading effect where they are all just stuck in a loop of validations?
Also... one other thing you might try, just as a test, it so Find/Replace the UltraCheckEditor with a regular CheckBox control and see if the problem still occurs. That, at least, will isolate the problem and tell you if it's the UltraCheckEditor or something in your code.
How would I do that? Right now the ultragrid is creating a checkbox column automatically because it is bound to a boolean in the view model.
Tanner Stevenson said:How would I do that? Right now the ultragrid is creating a checkbox column automatically because it is bound to a boolean in the view model.
Oh, sorry, I got lost for a minute there thought these were standalone controls.
If this is in a grid, then I wonder if maybe you have code in the InitializeRow which is setting the value of the CheckBox cell under some conditions and maybe it's triggering when you are clicking the checkboxes and immediately setting them back to their original values. That's a common cause of a problem like this where the value appears to just refuse to change.
Do you have code in InitializeRow? If so, then try returning from the event immediately without executing any of the code and see if that makes the problem go away.
Of course, if you are doing your validation in there and that's what's causing it, then that won't really tell us much.
I do not handle the InitializeRow event. I call for validation in a AfterCellUpdate event handler.
I have narrowed the issue down to a single line of code that gets fired when all pages have completed their validation:
EventAggregator.GetEvent<UpdateRunValidationEvent>().Publish(new UpdateRunValidationEventArgs(allIsValid));
Hopefully you are familiar with Microsoft Prism, but if not, its a loosely-coupled event framework.
If I comment the above line out, everything works as expected. If I just comment the code out of the event handler, the checkboxes still freeze, which indicates the problem has something to do with just the event aggregator. If I put a breakpoint in the event handler, I can successfully uncheck all the boxes after stepping out of the breakpoint each time. I have put the exact same code into my isolated test app, but it works correctly without the breakpoint. So maybe something is going on with threading? Is the ultragrid multithreaded?
It definitely doesn't access anything on the UI thread, my code only has references to it, it doesn't know about or modify my data. It is simply an engine we are using from another group but it was developed years ago, there is little documentation, and the source code is hard to find, so at this point it is pretty much a black box.
Unfortunately there was no strong resolution as to why this was happening, but at least I was able to figure out what caused it. Thank you for all your time and help!
If your background thread is accessing anything on the UI thread (like the grid or the grid data source) in any way, then that's a problem. Because the grid or the data source might be accessed by the UI Thread at any time and you have no control over that.
I figured out the issue, although I am still unclear why it was happening.
In the event handler for when all page validations had completed, I was calling the method of a background engine to get its status. This wouldn't throw an error to me, but if I didn't call that method, everything would work. So even though that method was completely unrelated to the underlying data of the grid, because it was accessing something on a different thread I guess that ended up disrupting the table? I'm still at a loss but I'm glad this silly error is resolved.
I am not familiar with Prism, but I think you are probably on to something with threading. The UltraWinGrid not mullit-threaded, nor is the DotNet BindingManager or any other DotNet controls that I am aware of. So If Prism or your code is doing anything on another to the grid or the data source on another thread, then that would certainly explain the behavior you are getting.