Slow scrolling in ComboBox - c#

I have a problem where scrolling in both a toolStripComboBox and regular ComboBox is really slow.
This happens both using the arrowkeys and the mouse scrollwheel. However, if I use the scrollbar it behaves as expected.
Here's the toolstrip combobox:
//
// toolStripComboBoxDeild
//
this.toolStripComboBoxDeild.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.SuggestAppend;
this.toolStripComboBoxDeild.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.ListItems;
this.toolStripComboBoxDeild.DropDownWidth = 121;
this.toolStripComboBoxDeild.Items.AddRange(new object[] {
"Allir"});
this.toolStripComboBoxDeild.Margin = new System.Windows.Forms.Padding(1, 0, 8, 0);
this.toolStripComboBoxDeild.MaxDropDownItems = 24;
this.toolStripComboBoxDeild.Name = "toolStripComboBoxDeild";
this.toolStripComboBoxDeild.Size = new System.Drawing.Size(200, 52);
this.toolStripComboBoxDeild.SelectedIndexChanged += new System.EventHandler(this.toolStripComboBoxDeild_SelectedIndexChanged);
I'm adding the rest of the data in the combobox with an SqlDataReader (not using a dataset because I'm comfortable using the sqlreader).
and the regular combobox:
//
// comboBox1
//
this.comboBox1.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.SuggestAppend;
this.comboBox1.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.ListItems;
this.comboBox1.FlatStyle = System.Windows.Forms.FlatStyle.System;
this.comboBox1.FormattingEnabled = true;
this.comboBox1.Location = new System.Drawing.Point(77, 17);
this.comboBox1.Name = "comboBox1";
this.comboBox1.Size = new System.Drawing.Size(221, 21);
this.comboBox1.TabIndex = 1;
this.comboBox1.SelectedIndexChanged += new System.EventHandler(this.comboBox1_SelectedIndexChanged);
Has anyone ever run into this problem? If so, what did you do to solve it?
EDIT
Changing the event handler to SelectionChangeCommitted solved the problem regarding the arrow keys, but not the mouse part.
The mouse scrolling behaviour is only aberrant when the mouse is over the dropdown list. When I click the combobox down arrow without moving the mouse and apply the scroll wheel, the list scrolls as expected.
EDIT 2
Figured out the problem with the mouse scrolling, turns out that it's the "Lenovo Mouse Suite" software and/or driver. Uninstalled it and now everythings just fine.
Thanks to Jeff Yates for showing me the SelectionChangeCommitted event.

When you use the keyboard, the selected index changes. When using the scroll wheel, the item under the mouse changes which will also lead to the SelectedIndexChanged event.
Therefore, if your event handler is intensive when the index changes, it will slow down the scrolling as it will run each time the selected index changes (i.e. each time your scroll with the mouse or keyboard). You should use SelectionChangeCommitted to handle when the selection changes instead as this will only fire once the combo is closed.
Update
So, you use the mouse wheel when the combo is NOT dropped down? If that is the case, then it is still the selection change handling as each roll of the wheel will change the committed selection. Scrolling when the combo is dropped down does not do this.
I recommend you add some kind of selection filter using a timer. You start (and restart) the timer each time the selection is committed. Only when the timer fires do you actually handle the selection change. This way, you scroll with the mouse wheel without incurring a selection penalty each time. Make sure to stop the timer when it fires, of course.

Related

Any click after clicking my richTextBox changing the size back to normal

When I click in my richTextBox, I run this code to make my textbox bigger for the user:
this.richTextBox1.Size = new System.Drawing.Size(500, 100);
Now I want any click after clicking my richTextBox to change the size back to the original:
this.richTextBox1.Size = new System.Drawing.Size(477, 26);
I can use the code above for each element mouse click event, but I am wondering if there is an easier way.
Just write the first code in richtextbox.enter event. And the second in richtextbox.leave event. Otherwise MouseClick is not a bad idea

WPF Button is static and does nothing

I'm designing a WPF Application in C# and I'm creating a grid with its controls at runtime. All of my controls work fine (Image, Textblocks, Labels), but my Button does not. It just sits there. When I move my mouse over it, it does nothing. When I click it, (w/ a click event handler) it does absolutely nothing! I've tried using different event handlers such as (Click, MouseDown, MouseUp). I have no clue what the problem is. Here's my code for the button:
Button AccessBtn = new System.Windows.Controls.Button();
AccessBtn.Content = "Access:";
AccessBtn.Margin = new Thickness(397, 571, 472, 41);
AccessBtn.Name = "AccessButton";
AccessBtn.Focusable = true;
AccessBtn.Click += (s, EventArgs) =>{
MessageBox.Show("Nothing here yet!");
};
grid.Children.Add(AccessBtn);
When you add children to the grid. They are added to row 0 and column 0.
So they will all be stacked on to each other. The button is no longer visible for the mouse event. You should put the button on top of the items or use row and columns to arrange the items. (Alternatively you might want to check a Canvas to position your elements.)

is it possible to rearrange controls in a flowpanel at run time?

so i have a flow panel and a button that adds listviews to it at run time. i have my doubleclick events set up - is it possible to set up some kind of click (or click and drag) event to rearrange the controls in the flow panel?
i know we can change the sort strategy (top down, left right) and wrap, but i was hoping for organization a user could simply drag the control from one spot and relocated somewhere else.
private void addNewWOButton_Click(object sender, EventArgs e)
{
ListView newListView = new ListView();
newListView.AllowDrop = true;
newListView.DragDrop += listView_DragDrop;
newListView.DragEnter += listView_DragEnter;
newListView.DoubleClick += listView_DoubleClick;
flowPanel.Controls.Add(newListView);
}
This will move a control to the top of the panel and move the remaining controls down.
FlowLayoutPanel1.Controls.SetChildIndex(myControl, 0);
For drag and drop re-ordering, you'll have to hook up drag and drop events for each control. On the drop event get the control being dragged and the index position of the target control. Then change the index with SetChildIndex. If your still working on this problem, I can dig up some code to show you.

Prevent ItemChecked event on a ListView from interfering with SubItemClicked using C#

I am using a in-place editable listview control for a project.
The editable listview adds a 'SubItemClicked' event so that each 'cell' can be edited.
lstSD2.SubItemClicked += new ListViewEx.SubItemEventHandler(lstSD2_SubItemClicked);
I also have the listview checkboxes enabled with a 'ItemChecked' event.
The problem is that once the 'ItemChecked' event is enabled double-clicking on any row fires the 'ItemChecked' event and prevents the 'SubItemClicked' event from firing.
Is there a way to enforce the need to actually 'check' the listview checkbox instead of firing whenever the row is double-clicked?
One possible solution is to disable the listview's 'DoubleClickActivation':
this.lstShuntData2.DoubleClickActivation = false;
The main drawback to this is that the users may find the listview a little too sensitive to any mouseclick.
.NET specifically adds this functionality to a ListView. Don't ask me why.
To get rid of it, listen for NM_DBLCLK reflected notification, and in the handler for that do this::
NativeMethods.NMHDR nmhdr = (NativeMethods.NMHDR)m.GetLParam(typeof(NativeMethods.NMHDR));
switch (nmhdr.code) {
case NM_DBLCLK:
// The default behavior of a .NET ListView with checkboxes is to toggle the checkbox on
// double-click. That's just silly, if you ask me :)
if (this.CheckBoxes) {
// How do we make ListView not do that silliness? We could just ignore the message
// but the last part of the base code sets up state information, and without that
// state, the ListView doesn't trigger MouseDoubleClick events. So we fake a
// right button double click event, which sets up the same state, but without
// toggling the checkbox.
nmhdr.code = NM_RDBLCLK;
Marshal.StructureToPtr(nmhdr, m.LParam, false);
}
break;
This is one of the many problems that ObjectListView solves for you. Even if you don't use the whole project, you can look at the source code and figure out how to do things yourself.

WPF create a list of controls that can be scrolled via the mouse but still remain functional

I have a list of controls that I am displaying via a WrapPanel and it horizontally oriented.
I have implemented a "Click and Drag" scrolling technique so that the user scrolls with the mouse via clicking and dragging.
Like so:
<Canvas x:Name="ParentCanvas" PreviewMouseDown="Canvas_MouseDown" MouseMove="Canvas_MouseMove">
<WrapPanel>
<WrapPanel.RenderTransform>
<TranslateTransform />
</WrapPanel.RenderTransform>
<!-- controls are all in here ... -->
</WrapPanel>
</Canvas>
Then in the code behind:
private Point _mousePosition;
private Point _lastMousePosition;
private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
{
_lastMousePosition = e.GetPosition(ParentCanvas);
e.Handled = true;
}
private void Canvas_MouseMove(object sender, MouseEventArgs e)
{
_mousePosition = e.GetPosition(ParentCanvas);
var delta = _mousePosition - _lastMousePosition;
if(e.LeftButton == MouseButtonState.Pressed && delta.X != 0)
{
var transform = ((TranslateTransform)_wrapPanel.RenderTransform).Clone();
transform.X += delta.X;
_wrapPanel.RenderTransform = transform;
_lastMousePosition = _mousePosition;
}
}
This all works fine
But what I want to do is make it so that when a users clicks to drag, the items within the WrapPanel dont respond (i.e. the user is only browsing), but when the user clicks (as in a full click) then they do respond to the click.
Just like how the iphone works, when you press and drag directly on an app, it does not open the app, but rather scrolls the screen, but when you tap the app, it starts...
I hope this makes sense.
Cheers,
Mark
I believe you'll need to capture the mouse. The problem is you'll be contending with the controls (such as Button) that will also be trying to capture the mouse.
In your MouseDown event (probably PreviewMouseDown actually) you can use e.MouseDevice.Capture(_wrapPanel, CaptureMode.Element). This should direct all mouse input to the _wrapPanel and not any subtree elements.
In your MouseUp event, you'll need to release the capture by calling e.Mousedevice.Capture(null). If no scrolling has taken place you'll want to send a "click" to the control that normally would have received the click which I'm not quite sure about. Perhaps you can use the Automation Peer classes to do this?
The trick is that certain controls will not work properly if you withhold mouse events from them. Consider a slider for example. How would the slider ever be usable inside a panel that works like this?
Another, and in my opinion better, solution is to:
Add a PreviewMouseDown handler in which you set Handled=true and record the parameters including the position and set a "maybeClick" flag (unless your "recursion" flag is set), and sets a timer.
Add a MouseMove handler that clears the "maybeClick" flag if the mouse moves more than an epsilon away from the position recorded for the PreviewMouseDown.
Add a PreviewMouseUp handler that checks the "maybeClick" flag - if true, it sets the "recursion" flag, does an InputManager.ProcessInput to re-raise the original PreviewMouseDown, and then clears the "recursion" flag.
In the timer, do the same thing as for PreviewMouseUp so the click will only be delayed a moment.
The net effect is to delay a PreviewMouseDown event until you have had time to check whether the mouse moved or not.
Some things to note about this solution:
Setting Handled=true on PreviewMouseDownEvent also stops the MouseDownEvent.
The recursive call is ignored in the PreviewMouseDown handler because the recursion flag is set

Categories

Resources