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.
So the binding isn't broken. I know this because I added another editable column to the table and i am able to edit that column and call the set accessor, even when the checkbox won't.
Hi Tanner,
Thank you for your feedback.
As you find by yourself, there are mainly two ways to create sample project, reproducing some issue. You can create it from scratch, as you did, or you can strip off the functionality of a complex sample reproducing the issue.
As you did not succeed to reproduce this issue with the first approach, go ahead and try to clear off the functionalities of your application. At some point you will either find the functionality forcing this to happen, or you will finish with a simple enough sample project. In both cases please send me the sample reproducing this behavior so I can try to find where the root of this issue is.
Based on the information I have it is really difficult to tell why this happens. So I do need a sample to look into.
Please let me know also the which the exact version of Infragistics for Windows Form you are using is.
Looking forward to your reply.
Hi Milko,
I have identified the source of this issue, however I am now trying to figure out how to reproduce it without using any of my companies proprietary libraries.
The version is 11.2 I believe.
If the CheckBox is simply losing it's binding at some point, then my guess is that there's an exception occurring. I've seen this happen if you bind to the CheckState property and your data source returns null. The CheckState is an enum and can't handle null and once the data source encounters a null or some other value that fails to convert, the DotNet BindingManager basically seems to give up and just stop trying to bind that control.
The solution would be to bind the Value property (which is an object and can handle null) instead of Checked or CheckState properties.
Or, an alternative solution would be to handle the Parse and/or Format events of the binding and convert the value into the something the bound property can work with.
So the strange thing about this behavior is the item that is unchecked can continue to be checked and unchecked. It is only the other items that can no longer be unchecked.
I have been able to identify the source of the problem, but I do not yet understand why it causes the issue. I am working on getting the basic example to reproduce the error, but it is a slow grind as I cannot use any of our proprietary libraries. In a nutshell, the problem arises when I call a validation routine after an item is selected or deselected. The validation routine resides in a singleton validator class and triggers an event that all pages subscribe to, notifying them when they need to validate. Each page will then handle the event and return whether or not the information in them is valid to the validator class. When the page in question responds to the event, it iterates through the row view models and updates a flag variable to display to the user if there is an error in the row. When this flag variable is changed, it will call OnPropertyChanged to update the view. If this method is called directly when an item is selected/deselected, without going through the event handler for the validator class, everything works fine. But as soon as the select/deselect calls the validator class' validation method, the checkboxes freeze. I have stepped through all of the subscribers to the validation event, and none of them throw an error, so it seems like the issue has something to do with the time/overhead involved with the validation of all pages in addition to updating the view models' flagged properties and calling OnPropertyChanged, including the view model who initiated this whole sequence.
Hopefully you were able to follow that. If not, I will continue to work on reproducing the issue.
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.
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?