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!
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!
Hi Tanner,
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.
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?