I've been fighting this bug all day and it annoyes me more with every minute I spend on it. Here's the deal: I have a ListView control and a Textbox control on a winforms form (.NET 1.1). With the Textbox you can edit a field of the object on the current selected row in the ListView. Easy right? I thought so too .
Not all values filled into the Textbox are valid. So I added a handler of the Validating event of the Textbox. When I tab away from the Textbox, the event gets fired and validation kicks in. If validation succeeds, the value is set in the object, otherwise validation fails and focus stays with the Textbox. When the SelectedIndex changes in the ListView and there is still a row selected, I fill the Textbox with the value of the particular field of the object currently being selected. This should work as Validating always should kick in when focus moves away from the Textbox.
But now the misery begins. Question: in which order are the following events fired when I'm editing the text of the Textbox and I click on another row in the ListView control: Textbox.Validating, Textbox.Leave, ListView.SelectedIndexChanged?
Answer: ListView.SelectedIndexChanged, Textbox.Leave, Textbox.Validating.
I'm sorry, but this is semantically wrong. What if validation fails? Focus should never move away from the Textbox before the Validating event. I now have to write some code which I consider a hack to work around this by keeping track of which object was previously selected in the ListView and I can't overwrite the 'currently selected row' when an edit is in progress, however I have to store somewhere that there is now a new selected object so after validation succeeds I have to set the Textbox to a new value.
When events were fired in the right order, this would be all fine. The low level reason for this error is the asynchronous behaviour of winform controls: under the hood they're (most of the time, there are exceptions) Win32 controls which solely respond to Win32 messages. So if you click on the ListView, the control receives a message from Windows, it acts on it and fires an event. Focus moves away from the Textbox after this and this will cause a message to be delivered for the Textbox, which will cause a .NET event. But much too late.
So if you set up a similar setup, be aware of this.