This thread looks to be a little on the old side and therefore may no longer be relevant. Please see if there is a newer thread on the subject and ensure you're using the most recent build of any software if your question regards a particular product.
This thread has been locked and is no longer accepting new posts, if you have a question regarding this topic please email us at support@mindscape.co.nz
|
I am using some custom editors for some custom data types. The editors all derive from a common base and display the current value in a viewer box that appears like a combo-box. When the user clicks the drop-down the actual editor is displayed in a popup. When the user finishes editing the new value is constructed (if necessary) and copied back to the viewer box (or discarded if Esc was pressed). When I use these viewer/editors in the DataGrid I find that when the iser clicks outside the editor (e.g., in another cell) then the grid leaves edit mode and dumps the editor before any such "edit complete" processing can occur. I could not find any reliable event to get notification before this occurred. I did finally get this to work as follows: 1) Modified base editor class to inspect the visual tree to see if it is contained in a DataGridCellContainer. 2) If in a DataGridCell container then when the popup opens it starts previewing all mouse down events for the window: Mouse.AddPreviewMouseDownHandler(this.GetWindow(), OnPreviewMouseDownHandler); 3) In the preview mouse down handler we check if the source of the event is outside the editor (popup or viewer), and if so does the edit complete processing. At first I thought that I could use the LostFocus even on my editor, but I find I could not get this to work reliably. This is partly because the Focus call in DataGridCellContainer.AttemptToFocusEditor (line 521) actually causes a LostFocus event to occur on the Editor, and various LostFocus events can occur as the user clicks around inside the editor, and I can't seem to reliably distinguish which ones are going to cause editing to end (since as far as I can tell I can't find out where focus is going to from this event). Anyway, I don't think my solution of previewing all mouse clicks in the window is a good one, so I am hoping I can get some advice on a better way to tell that my editor need to do end-edit processing before it gets dumped. Possibly a new DataGrid event such as OnEditEnding (passing the editor if available, or the DataGridCellContainer). Thanks Peter |
|
|
Hello Peter This usually works for me: Rather than listening to LostFocus, listen to the IsKeyboardFocusWithinChanged event. This will only change in two scenarios: The main control or one of the internal controls gains focus, or main control and NONE of the internal controls have focus anymore, including any controls within a Popup. Sounds like the perfect place to put the ultimately-lost-focus logic. I have tested this out in the DataGrid and it worked fine. If you don't need the logic to run when the control gains focus, simply check that IsKeyboardFocusWithin is false. Jason Fauchelle |
|
|
Hi Jason, Thanks for your response. I did manage to get things working using IsKeyboardFocusWithinChanged as you suggested. While I think I have my problem solved now, I don't think this is the "perfect place" for such code for a couple of reasons: 1) This requires the programmer to have fairly intimate knowledge of how the grid works--that the way to get notified that it's time to save any edited value (when hosted in a DataGrid) is to monitor IsKeyboardFocusWithinChanged. To use my editors with your DataGrid I have to make them DataGrid aware so that in the Popup.Opened handler I have to walk up the visual tree to see if I am hosted in a DataGridCellContained, and if hook the IsKeyboardFocusWithinChanged handler. 2) I find that if I set focus to one of the sub-controls in my editor in the Popup.Opened then the IsKeyboardFocusWithinChanged is immediately triggered with the new Value of false, triggering my "closing" logic prematurely. This is because of the setting the Focus to the DataGridCellContainer in AttemptToFocusEditor. I can solve this problem by setting Focusable to false on the DataGridCellContainer, but I don't know if that has other ramifications. Anyway, I am okay with the current way it works--I just think it isn't ideal. Peter |
|
|
Hello Peter 1) You should not need to hack the VisualTree. You can listen to the IsKeyboardFocusWithinChanged event on your own control regardless of if a DataGridCellContainer is present. This will decouple your control from the DataGrid. 2) Please follow my advice for number 1, and let me know if the second issue is still a problem. Great to hear that this solved the main problem. Jason Fauchelle |
|
|
Hi Jason, Sorry I probably wasn't clear in my previous post. I am listening to IsKeyboardFocusWithinChanged on my own editor control, not on the DataGridCellContainer. The reason I am checking the visual tree is to see if my editor control is hosted in a DataGrid, because only then do I need to listen to IsKeyboardFocusWithinChanged (my editor controls are not just for use in the DataGrid). Also I find that in the case where I want to set focus to a particular sub-control within my editor control (in Popup.Opened) I find that it causes problems because after I set the focus the DataGridCellContainer.AttemptToFocusEditor subsequently sets focus back to the DataGridCellContainer, which triggers an immediate IsKeyboardFocusWithinChanged (to false), which both prematurely causes my "end edit" processing to run and clobbers the sub-control focus I tried to set. I can solve this problem by setting DataGridCellContainer.Focusable=false. So I believe I am following your advice, but need to access the DataGridCellContainer to work around these issues. If there were appropriate events at the grid level then it just seems like it could be much cleaner. A "BeginingEdit" occuring after the DataGridCellContainer has been initialized for editing would provide a good place to set focus inside the editor (for example). An "EndingEdit" occuring just before IsEditing is set to false on the DataGridCellContainer would provide a good place to update the bound property on the editor, if needed. Both events could pass the editor control in the EventArgs. Honestly Jason I am fine with the way things are now because it is working fine for me. I am just making a suggestion for how I think the API could be improved. If it doesn't make sense to you then I am fine with leaving things as they are. Your support is great! Peter |
|
|
Hello Peter I'd just like to finish off with this final suggestion. I was thinking your control should function the same if you listen to the IsKeyboardFocusWithinChanged event all the time - even when it is not in the DataGrid. If it does work correctly when listening to this event outside a DataGrid, then this would save you from looking through the Visual Tree. Focusing the cell inside the AttemptToFocusEditor method does not seem right, so I've removed this for the next nightly build. This would mean you don't need to set IsFocusable to False anymore. I have noted down your API suggestions to look into later. Jason Fauchelle |
|
|
Hi Jason, With the removal the focus inside the AttemptToFocusEditor it now works find without me setting IsFocusable to false on the container. Thanks. I'm keeping the detection of a DataGrid host via the visual tree because the processing associated with it may be undesirable in some cases outside the DataGrid--commiting an edit prematurely so that if the user ended an edit by pressing Esc the change would already have been committed (because the popups may use StaysOpen=true). Peter |
|