I am trying to model the behavior of a ComboBox dropdown (or other drop downs for that matter, including context menus) where the drop down closes when you click anywhere else, even on something that can't be focused.
I've tried subscribing for events such as MouseCaptureChanged, LostFocus, and Leave. I have a custom UserControl which is acting as a dropdown and I just want to close it up when the user clicks anywhere else.
This seems like something that's done in many controls so I'd be surprised if there wasn't a simple way to do it.
So far the overcomplicated methods I can come up with to do this are using pinvoke and the SetCapture() function, or to create a MessageFilter. If these are the only options I am not sure which is better.
The ComboBox is constructed from 2 controls.
Base - visible when not active (Control)
DropDownList - visible during edit mode or list selection mode (Window or Form)
Normally the Base is visible. When the user clicks onto the ComboBox, the Base control hides and the DropDownList control shows up. This switch is done on the background, so for the user it seems the control just expanded.
The event you want to catch is done through the DropDownList Window. If you click somewhere onto your client area, the DropDownList Window receives the WM_KILLFOCUS event through it's WndProc(Message% m) method. Then sends to the parent window (the Base control) a WM_COMMAND (OCM_COMMAND) message with WParam=526318 (HIWORD(WParam)=8) and the Base control knows he should hide the DropDownList Window.
So, what you need to do is implement the additional DropDown Window and catch the WM_KILLFOCUS event.
The templates of the controls you've mentioned are using for the dropdown lists a popup as a container with the StaysOpen property set on false (which is the default i think).
ComboBox template example
Related
I have a windows forms application and added a menu to maneuver between few User Controls. I am using the events: Click, MouseEnter and MouseLeave.
In every event I am changing the BackgroudImage and what i want to achieve is that when the image did change after the click event, the image will stay. And I was thinking using the User Control properties to determine if he is Shown or not (as I am using the Show() and Hide() methods).
Tried using the Visible, Focused and Enabled properties but none of them changing after hiding or showing the User Control.
How can i determine if the User Control is shown or not?
The property IsHandleCreated gets true when the control is loaded. Try to use this property.
reference document :https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.control.ishandlecreated?view=netframework-4.7.2
Apparently when the form loaded, the default Visible property is set to True even though I really don’t see all of the User Controls (they are one on each other).
So I added a show and hide method in the form load event and the visible property works like a Charm.
Thank Franck
I'm struggling to make a custom autocomplete style control for my application using a list view. In one form, the custom control is working as expected, however in another, when clicking on the ListView, rather than the ListViewItem being selected, the first TextBox in the form is selected instead.
Rather than clog up the question with a wall of code, here is the code for the AutoCompleteListView.
Here is an image of the form. Items are redacted due to data protection:
Also, here is a .gif showing the behaviour of the form. What I'm doing in the aformentioned gif is attempting to click on the first item within the ListView, however, as I do that, focus changes to the first text box in the form. This same behaviour occurs when clicking on any item, in any of the 3 text boxes.
I have attempted to trace the events using RuntimeFlow to watch as events fire, but it has not provided any clarity as to what is actually happening. If anyone could point me in the right direction, that'd be greatly appreciated.
My first guess is in ItemClick you are setting visibility to false, which means something else in the form needs focus, ie the textbox. So do a textbox.focus() in ItemClick to the desired textbox. And given that you will not have access to the parent form in this class, I recommend you make an OnClose event in the AutoCompleteListView and subscribe to it in the parent form, to set the focus to somewhere.
I have a Windows Forms application and I want to be able to show a 'post-it note' type thing when the user does a specific action.
For example: The user does something which automatically hides a control.
My application should:
o Pop up a post it note which explains what happened.
o Hide the post it note again when the user clicks anywhere on the form.
I have implemented the post it note as a simple panel with a label in it, which shows and hides when specific things happen.
However, I can't seem to capture the OnClick event of the parent UserControl. The parent control is a nested control, containing a split container, one side of which contains the panel and a tab control, each of which contains a user control with various things in it.
Apart from handling the click event of every single child control, can anyone think of an event that I can capture on the parent control that I can use to hide the post it note when the user clicks anywhere in the parent control?
Thanks,
Rik
That's what the Capture property was designed to do. Set it to true when you pop up the note. Any mouse events will now be directed to your control, even if the mouse moves outside of the window. This is also the way that, for example, the combobox dropdown list works. Keep in mind that it is only good for one click.
If the popup contains any controls itself then mouse capture isn't the solution. Make it an owned form instead and simply call Close() in an event handler for the Deactivate event.
There is bubling of events in windows form, while you click on child event, the event is raised for child, and then for parent. Unless you specify "handleEvnet" property to true. So just leave it false, untill event reaches parent.
I have a windows form application that has two main panels: The one on the left is a narrow strip which has a series of radio buttons. The panel on the right houses a Tabcontrol, which has multiple Tabpages added to it which the user can select among along the top. Each of these tabpages themselves has about 7 DataGridViews added to it. Each DataGridView has about 5-6 columns of text, with a variable number of rows (10-500). The data added to it was done directly to the DGV itself, ie using the DGV.Rows.Add() method, passing an object array, not via a datasource.
When a user selects a different tab page, the datagridview that gets shown is dependent on the radiobutton that is selected on the left. I accomplish this by handling the SelectedIndexChange event of the tabcontrol and each of the radiobutton's CheckedChange event.
Within the SelectedIndexChange event of the tabcontrol, I programmatically checked the currently selected radioButton. Then within the radiobutton's CheckedChange event, I iterate through all of the DataGridViews on the TabControl's selectedTab and hide all those that don't match the one corresponding to the selected radiobutton.
My issue is everytime the user starts changing among a lot of tabs, or tries to view a DGV that has many rows, the program would throw the following error:
System.ComponentModel.Win32Exxception: Error creating window handle.
Does anyone know what would cause the above error? My initial suspicion was that when I change to a different tabpage, the DGV on the original tabpage i was on was still in memory, but when I try calling .Dispose() on it, the DGV just disappears. It may be I am missing something fundamental here.
The problem is that you are probably trying to show a disposed DataGridView.
Do not dispose any Control in your form unless you are previously removing it from the appropiate Container.Controls collection (because you do not need it anymore and/or you plan adding a new one in its place). Otherwise dispose any controls when closing and disposing the Form that contains them if necessary.
In order to show the proper DataGridView depending on selected tab and user options use the Visible property or dynamically add and remove the needed controls to the container's Controls collection (in this case TabPage.Controls.
If its not that then maybe you have a "control leak" (probably event handler holding the object) and you are exceeding the windows handle limit for any given application (10.000 I think it is).
For a project I am working on, I have some values in a PropertyGrid that are many lines long. I want the user to be able to double-click a value in the grid, which will bring up my custom UI window. I already have it set up so that the UI works when the [...] button is clicked, but I also need it to show up directly if any grid item is double-clicked.
On a side note, looping through the controls of the PropertyGrid and assigning Click/Mouse events to them allows this to happen when the property name is clicked, but still does not capture the click when the property value is clicked. Any suggestions?