Populating a DataGridView on-the-fly (VB.NET) - vb.net

I have a DataGridView which reads data from a custom (CSLA) list object. The dataset might have 100,000 records, and obviously I don't want to show them all at once because, for one, it would take ages to load.
I think it would be nice if I could read the first (for instance) 20 records, and make it so upon scrolling to the end of the list, it reads the next 20 and adds them to the DataGridView.
I have experimented with various ways of doing this, mostly using a custom class inheriting from DataGridView to capture scroll events and raising an event which adds new records. I will include the code below:
Public Class TestDGV
Inherits DataGridView
Public Sub New()
AddHandler Me.VerticalScrollBar.ValueChanged, AddressOf vsScrollEvent
AddHandler Me.RowsAdded, AddressOf vsRowsAddedEvent
End Sub
Private Sub vsScrollEvent(ByVal sender As Object, _
ByVal e As EventArgs)
With DirectCast(sender, ScrollBar)
If .Value >= (.Maximum - .LargeChange) Then
RaiseEvent ScrollToEnd()
End If
End With
End Sub
Private Sub vsRowsAddedEvent(ByVal sender As Object, ByVal e As EventArgs)
ScrollbarOn()
End Sub
Public Event ScrollToEnd()
Public Sub ScrollbarOff()
Me.VerticalScrollBar.Enabled = False
End Sub
Public Sub ScrollbarOn()
Me.VerticalScrollBar.Enabled = True
End Sub
End Class
Though this (sort of) works, it can be buggy. The biggest problem was that if you used the mouse to scroll the DataGrid, it would get stuck in a loop as it process the scrollbar's ValueChanged event after the data was added. That's why I added ScrollbarOff and ScrollbarOn - I call them before and after getting new records, which disables the scrollbar temporarily.
The problem with that is that after the scrollbar is re-enabled, it doesn't keep track of the current mouse state, so if you hold down the 'Down' button with the mouse (or click on part of the scrollbar) it stops scrolling after it has added the new records, and you have to click it again.
Also, it doesn't seem a particularly elegant way of doing things.
Has anyone ever done this before, and how did you achieve it?
Cheers.

Perhaps you could reduce your result set and use the << and >> kind of paging controls. Nerd Dinner demo introduced an elegant solution using LINQ:
//
// GET: /Dinners/
// /Dinners/Page/2
public ActionResult Index(int? page)
{
const int pageSize = 20;
var upcomingDinners = dinnerRepository.FindUpcomingDinners();
var paginatedDinners = upcomingDinners.Skip((page ?? 0) * pageSize)
.Take(pageSize)
.ToList();
return View(paginatedDinners);
}

What about using the virtualproperty of the DataGridView?
See Implementing Virtual Mode with Just-In-Time Data Loading in the Windows Forms DataGridView Control for an example.

Related

Most efficient way to programmatically update and configure forms and controls

I am looking for a way to prevent user form controls from appearing one by one when I'm programmatically adding them and for ways to enhance application performance and visual appeal.
Say, I have a Panel_Top in which I programmatically add comboboxes. What is happening is that they appear one by one as they are created and I am looking for a way to suspend the refreshing of the panel and or user form to make all of those programmatically added comboboxes to appear at the same time and faster than it happens right now.
I've tried suspendlayout which doesn't do anything for me or maybe I'm doing it wrong.
MyForm.PanelTop.SuspendLayout = true
And also I've tried to set the Panel_Top to invisible like:
MyForm.Top_Panel.visible = false
Which kind of sorta looks and performs better, or it might be a placebo.
What is the correct approach to this problem?
PS: I do have form set to doublebuffer = true, if that matters
What I tend to do is create a loading modal to appear on top of the form rendering the controls that need to be created/made visible, this can optionally have a progress bar that gets incremented as the control is created/shown. With the loading modal running, the container that needs to add the controls starts with SuspendLayout, adds the controls, and then finished with ResumeLayout.
This makes it so that controls are added/shown while giving the user a visual indicator that something is going on behind the scenes.
Here is a phenomenal example of a loading modal: https://www.vbforums.com/showthread.php?869567-Modal-Wait-Dialogue-with-BackgroundWorker and here is an example of using it:
Private ReadOnly _controlsToAdd As New List(Of Control)()
Private Sub MyForm_Show(sender As Object, e As EventArgs) Handles MyBase.Shown
Using waitModal = New BackgroundWorkerForm(AddressOf backgroundWorker_DoWork,
AddressOf backgroundWorker_ProgressChanged,
AddressOf backgroundWorker_RunWorkerCompleted)
waitModal.ShowDialog()
End Using
End Sub
Private Sub backgroundWorker_DoWork(sender As Object, e As DoWorkEventArgs)
Dim worker = DirectCast(sender, BackgroundWorker)
For index = 1 To 100
_controlsToAdd.Add(New ComboBox() With {.Name = $"ComboBox{index}"})
worker.ReportProgress(index)
Threading.Thread.Sleep(100) ' Zzz to simulate a long running process
Next
End Sub
Private Sub backgroundWorker_ProgressChanged(sender As Object, e As ProgressChangedEventArgs)
Dim percentageCompleted = e.ProgressPercentage / 100
' do something with the percentageCompleted value
End Sub
Private Sub backgroundWorker_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs)
PanelTop.SuspendLayout()
PanelTop.Controls.AddRange(_controlsToAdd.ToArray())
PanelTop.ResumeLayout()
End Sub
SuspendLayout() is the correct way to handle this with WinForms.
But first of all, this is a function you call, and not a flag you set.
Secondly, don't forget to call ResumeLayout() at the end of the changes.
Finally, you need to ensure you only call them once when you start to change around the controls in the panel and then again at the very end. If you use them with every control you won't get any benefit.
So the pattern might look something like this:
Public Sub SomeMethod()
PanelTop.SuspendLayout() ' Prevent the panel from updating until you've finished
' Make a bunch of changes
PanelTop.Controls.Clear()
For Each ...
PanelTop.Controls.Add( ... )
Next
PanelTop.ResumeLayout() ' Allow the panel to show all the changes in the same WM_PAINT event
End Sub
You also need to ensure you don't have anything in there like DoEvents()/Invalidate() that might invoke the windows message loop and cause the form to redraw itself.

How to make a user select an image and save the image as a variable?

I am trying to create a VB.net form where the user can click on a button and it is associated with a specific image and when the user clicks the image and then clicks select it will add it to a variable.
If you need more information please let me know (this is the image of my form)
I wanted to know:
how to assign an image to a button ( so when you click it, it means that the user wants that image) I am not sure if my method is correct
how to assign the image that was selected to a variable (so that once the variable is called it will output the image)
and how to end the form once the image is selected. (once use clicks the select button it should end the form, or if the user clicks cancel it should end the form).
Public Class Form1
Private Property SelectedPictureBox() As Image
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Controls.OfType(Of ButtonPictureBox).ToList().ForEach(
Sub(box)
AddHandler box.Click, AddressOf AllButton_Click
End Sub)
End Sub
Private Sub AllButton_Click(sender As Object, e As EventArgs)
SelectedPictureBox = CType(sender, ButtonPictureBox).PictureBox
End Sub
Private Sub GetBtnSelect_Click(sender As Object, e As EventArgs) Handles GetBtnSelect.Click
If SelectedPictureBox IsNot Nothing Then
MessageBox.Show(SelectedPictureBox.Name)
Else
MessageBox.Show("Please select an image")
End If
End Sub
Private Sub BtnTropicalFloral_Click(sender As Object, e As EventArgs) Handles BtnTropicalFloral.Click
SelectedPictureBox = PictureBoxTropicalFloral.Image
End Sub
Private Sub BtnLightGeode_Click(sender As Object, e As EventArgs) Handles BtnLightGeode.Click
SelectedPictureBox = PictureBoxLightGeode.Image
End Sub
Private Sub BtnStripes_Click(sender As Object, e As EventArgs) Handles BtnStripes.Click
SelectedPictureBox = PictureBoxStripes.Image
End Sub
Private Sub BtnAuroraBorealis_Click(sender As Object, e As EventArgs) Handles BtnAuroraBorealis.Click
SelectedPictureBox = PictureBoxAuroraBorealis.Image
End Sub
Private Sub BtnDiagonals_Click(sender As Object, e As EventArgs) Handles BtnDiagonals.Click
SelectedPictureBox = PictureBoxDiagonals.Image
End Sub
Private Sub BtnComb_Click(sender As Object, e As EventArgs) Handles BtnComb.Click
SelectedPictureBox = PictureBoxComb.Image
End Sub
Private Sub BtnMountain_Click(sender As Object, e As EventArgs) Handles BtnMountain.Click
SelectedPictureBox = PictureBoxMountain.Image
End Sub
Private Sub BtnLandscape_Click(sender As Object, e As EventArgs) Handles BtnLandscape.Click
SelectedPictureBox = PictureBoxLandscape.Image
End Sub
Private Sub BtnGradient_Click(sender As Object, e As EventArgs) Handles BtnGradient.Click
SelectedPictureBox = PictureBoxGradient.Image
End Sub
Private Sub BtnAbstract_Click(sender As Object, e As EventArgs) Handles BtnAbstract.Click
SelectedPictureBox = PictureBoxAbstract.Image
End Sub
Private Sub BtnGeode_Click(sender As Object, e As EventArgs) Handles BtnGeode.Click
SelectedPictureBox = PictureBoxGeode.Image
End Sub
End Class
My VB is a bit rusty, so I'll have to give the answer in C#. I'm sure you'll get the gist, and will be able to translate it into VB.
First of all: whenever you see that you are repeating things, for instance by copy-paste, you should stop, and rethink your design: maybe it would be better to create a method for this, or an object.
All your PictureBox/Button combinations have some common behavior. This means that you should think of creating a class for it.
In your case, you have the combination of a Button and a PictureBox. You want to be able to set and get an Image. The PictureBox will show this image. Finally you want to be notified if the operator clicks the Button.
In the event handler of this Notification you want to know which pictureBox/Button combination sent the event. You get the image from this combination and close the form.
In WinForms, whenever you want to have a class that is a combination of several controls, you make a UserControl.
In Visual Studio, in the solution control, right click on the project (not the solution!) and select: Add new Item. Select to add a new User Control. Think of a proper name, I'll call this ImageSelectionControl
Use the visual studio designer to give ImageSelectionControl the proper size. Add a PictureBox and a Button. Also use the visual studio designer to add an EventHandler for if the operator clicks the button.
In the code of the User Control add the property to Set / Get an Image. The Image that you set will be displayed in the PictureBox; the Image that you get is the image that is displayed in the PictureBox.
Here comes the first chunk of C#:
public Image Image
{
get => this.pictureBox1.Image;
set => this.pictureBox1.Image = value;
}
I think in VB this will be very similar.
Now you want that users of your control (= software, not humanoids) get notified that the operator selects an image. Officially, you even want to hide how the operator selected this image: all you want to say: "Hey, the operator selected my image!"
Normally you would do this using an event:
The 2nd piece of C#:
public event EventHandler ImageSelected;
The event won't have any data. It will only say: "Hey, the operator selected my image!". The event event handler will have to find out which user control raised the event, and fetch the image.
Ok, raise the event:
private void OnImageSelected()
{
this.ImageSelected?.Invoke(this, EventArgs.Empty);
}
It will be a bit more difficult to translate this into VB. What it does, it checks if there is at least one person who wants my events. If so it raises the event. with two parameters: the sender (which is me), and no parameters. Later we will see how the receiver of the event works.
Finally: if the operator clicks the button, he indicates that he wants to select the image in the user control, and thus OnImageSelected needs to be called
private void ButtonSelect_Clicked(object sender, EventArgs e)
{
this.OnImageSelected();
}
We've finished creating the UserControl. After Compilation you will find it in visual studio designer toolbox.
So we'll go to the form that will have to display the eleven PictureBox-Button combinations. Let's call this form: ImageSelectionForm.
Using Visual Studio Designer, add 11 ImageSelectionControls. If you know already at design time which control will show which image, you can do this in the designer, similarly to how you set the text or the background of a button.
If you only know at run-time which control should show which image, consider to add a method, for instance if you want to load it from file:
void ShowImage(ImageSelectionControl imageSelectionControl, string imageFileName)
{
Image image = this.LoadImageFromFile(imageFileName);
this.imageSelectionControl.Image = image;
}
Or maybe you have a different method to decide which ImageSelectionControl should displaye which image. I guess you get the gist.
Almost done. ImageSelectionForm needs to be notified about the selected image, so just like you would do with a button, you need to subscribe to event ImageSelected.
In the constructor or ImageSelectionForm, subscribe to the events:
private ImageSelectionForm()
{
InitializeComponent();
// subscribe to events
this.controlBlueGeod.ImageSelected += this.ImageSelected;
this.controlAbstract.ImageSelected += this.ImageSelected;
...
}
Of course, you can put all ImageSelectionControls in one list and use foreach to subscribe (that is too much VB for me, no idea how to do this)
The event handler:
void ImageSelected(object sender, EventArgs e)
{
// we know that the sender is the one that holds the selected images:
ImageSelectionControl imageSelectionControl = (ImageSelectionControl)sender;
We will be closiing the form very soon, so we will have to remember this selected image somewhere in a property:
public Image SelectedImage {get; set;}
So continuing the event handler:
this.SelectedImage = imageSelectionControl.Image;
this.DialogResult = DialogResult.OK;
this.Close();
}
So the selected image is saved. The dialog result is set to indicate that an image was selected, not cancel clicked. And the form is closed.
Showing the form and process the selected image
The form that has to show ImageSelectionForm has a procedure:
private void ShowImageSelectionForm()
{
using (ImageSelectionForm dialog = new ImageSelectionForm())
{
// show the dialog and process the result:
DialogResult dlgResult = dialog.ShowDialog(this);
if (dlgResult == DialogResult.OK)
{
this.ProcessSelectedImage(dialog.SelectedImage);
}
else
{
// TODO: process cancel
}
}
}
There is one memory leak: if you created a lot of images, all images need to be Disposed after usage. Best is to by overriding Component.Dispos(bool)
ImageSelectionControl:
protected override Dispose (bool disposing)
{
if (disposing && this.Image != null)
{
this.Image.Dispose();
}
}
ImageSelectionForm:
protected override Dispose (bool disposing)
{
if (disposing)
{
this.controlBlueGeod.Dispose();
this.controlAbstract.Dispose();
...
} ​
​}
This is quite a nuisance for 11 controls. Therefore quite often a Form or a UserControl has a System.ComponentModel.IContainer components. If you add your ImageSelectionControls to this container, then the ImageSelectionControls will be automatically disposed when ImageSelectionForm is disposed.
​
You have two Controls that work together to allow users to preview and select one or more Images in the UI. When you have this kind of scenario, build a UserControl that contains all the required UI elements and the logic used perform this action.
To build this UserControl:
Open the Project menu and select Add User Control...
Right away, set (in this order):
AutoScaleMode = Dpi
Font = Segoe UI, 9pt
BackColor = Color.Transparent
Set a Size that you think is the minimum required to show an Image and a Button
When you have found the right size, set also the MinimumSize to this value
Add a Button to the UC, configure it as needed, set its Width as the Width of the UC minus 4 pixels. Position the Button at the bottom of UC, 2 pixels to the left and set Anchor = Bottom, Left, Right
Add a PictureBox, same Width and Left location as the Button. Set the Height as required, then Anchor = Top, Bottom, Left, Right
Design completed. Build the Project.
Now, your UserControl needs to provide means to set an Image to the PictureBox and the Text of the Button.
You can add two Public Properties of Type Image and String that, when a value is assigned, set the PicureBox.Image property and the Button.Text property.
Also, when the Button is clicked, the UserControl needs to notify that the User has performed a selection, so whatever other code needs to do something with this information, will be able to act on it.
In an event-driven UI, you make your UC raise a public event that interested parties can subscribed to, to receive a notification that something happened.
You just need to define a Field of Type Event and give it a name. In this case, e.g.:
Public Event ImageSelection As EventHandler
When the Button is clicked, you raise the event:
RaiseEvent ImageSelection(Me, EventArgs.Empty)
The sample UserControl is named ImagePicker, the PictureBox is named picImage and the Button is btnSelectImage
Public Class ImagePicker
Public Event ImageSelection As EventHandler
Private m_Picture As Image = Nothing
Private m_Title As String
Public Property Picture As Image
Get
Return m_Picture
End Get
Set
m_Picture = Value
picImage.Image = m_Picture
End Set
End Property
Public Property Title As String
Get
Return m_Title
End Get
Set
m_Title = Value
btnSelectImage.Text = m_Title
End Set
End Property
Private Sub btnSelectImage_Click(sender As Object, e As EventArgs) Handles btnSelectImage.Click
RaiseEvent ImageSelection(Me, EventArgs.Empty)
End Sub
End Sub
In your Form (for example), you can the subscribe to this event to receive a notification that the User has selected the Image of one of your UserControls.
When the event is raised, the sender object is the UserControl that raised the event. You can then cast sender to your UserControl Type and read the Public Property that references the Image you have assigned to it.
In a Form, you can add some of your UserControls to a FlowLayoutPanel (in the example, named flpPreviews), which will take care of the layout of these Controls.
While adding the UserControls, you set their Public Properties and also subscribe to the Public event.
When the event is raised, cast sender to ImagePicker and read its public Picture property to get the reference of the Image selected:
Public Class SomeForm
Public Sub New()
InitializeComponent()
' Add three ImagePicker UserControls to a FlowLayoutPanel
For i As Integer = 0 To 2
Dim picker = New ImagePicker()
picker.Picture = [Some Image]
picker.Title = "Some Title"
' Subscribe to the event
AddHandler picker.ImageSelection, AddressOf ImageSelectionChanged
flpPreviews.Controls.Add(picker)
Next
End Sub
Private Property SelectedImage As Image
Private Sub ImageSelectionChanged(sender As Object, e As EventArgs)
SelectedImage = DirectCast(sender, ImagePicker).Picture
' Show the selected Image in a PictureBox, child of the Form
picSelected.Image = SelectedImage
End Sub
End Class

Cefsharp download window for showing progress in VB.Net

I am creating a browser using Cefsharp in VB.Net, and I have been trying to create a download window that shows the progress of the current download. I don't know if I am doing something wrong or if it is the way CEF works, but I put in a download handler by adding browser.DownloadHandler = New DownloadHandler to Form1_Load and creating a new class like this (with downloading being the form I created for showing the progress):
Public Class DownloadHandler
Implements IDownloadHandler
Public Function OnBeforeDownload(downloadItem As DownloadItem, ByRef downloadPath As String, ByRef showDialog As Boolean) As Boolean Implements IDownloadHandler.OnBeforeDownload
downloadPath = downloadItem.SuggestedFileName
showDialog = True
downloading.Show()
Return True
End Function
Public Function OnDownloadUpdated1(downloadItem As DownloadItem) As Boolean Implements IDownloadHandler.OnDownloadUpdated
My.Settings.downloadpercent = downloadItem.PercentComplete.ToString
Return False
End Function
End Class
On the downloading form I have this code for showing the progress:
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
Dim percentcomplete As Integer = My.Settings.downloadpercent * 5
Me.PictureBox1.Size = New Size(percentcomplete, 25)
End Sub
Private Sub downloading_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Timer1.Start()
End Sub
This may not be the best way to show a ProgressBar, but I have a picture box that just has a green bar, and the total width of the form is 500px. The code is telling it to read the PercentComplete setting put in My.Settings.downloadpercent, multiply it by 5, so when the progress in 100%, it will go across the whole form.
The problem is that the ProgressBar is not being updated to show the current progress. It goes a little bit, but then it just stops. Am I doing something wrong, or is OnDownloadUpdated not a good place to put that? Any suggestions of how to fix this?
Edit:
I am using CefSharp 39.0.0-pre03. Also, when the save file dialog comes up, no matter if you click Save or Cancel, the browser always triggers a LoadError, so it loads the custom HTML error page I made, and since it requires a URL for loading HTML, I put in "http://rendering/"... So I guess that would be a domain change. That issue (in the comments) could be the problem, but then we also need to figure out why it is triggering a LoadError.
A simple solution that may be of interest to those who faced the same or similar problem:
Declare Public your Picturebox, in a module:
Module Module1
Public PictureBox1 As New PictureBox
End Module
In MainForm you can declare the attributes you want (after the InitializeComponent). Example:
With PictureBox1
.BorderStyle = Border3DStyle.Flat
.Image = Bitmap.FromFile(YourImageFileName)
'......
End With
In the DownloadHandler Class:
Public Function OnDownloadUpdated1(downloadItem As DownloadItem) As Boolean
Implements IDownloadHandler.OnDownloadUpdated
Dim percentcomplete As Integer=downloadItem.PercentComplete * 5
PictureBox1.Size = New Size(percentcomplete, 25)
Return False
End Function

vb.net event handle not working

I am new in vb.net, I have a data collection application that use scan data in warehouse. it is window system, I couldn't get the event handling work. Please help me find what is wrong with my program below.
Here is the project, In the app I have a scanner class that I use it to scan barcode, and when scan happens raise an event to let the forms know. many forms can use scan data. But only the form visible on top will handle the scanned data.
I have 2 forms order form and ticket form, they both handle the scandata event. First order form handles scan data event and fill in the scanned order text field, then it automatically launches ticket form, and the ticket form suppose to handle the scan data event and post data on ticket form.
The Order form handles the event fine, the problem is after launching the ticket form automatically, it seems cannot associate to the event, the event seems still with the Order forms, So,ticket form not reveiving it and does nothing.
I have to use LaunchTickets() in order form to get to ticket due to business request, How do I implement this to get the event associate to correct form whatever the form visible on top in my application? I don't know if there is a way to get around, if not, what is the best way to implement this? please help me to get this work.
Public Class ClsComPort
Public Shared Event NewScanData(ByVal ScanData As String)
Public Function InitializebcrScanner() As Boolean
AddHandler mySerialPort.DataReceived, AddressOf mySerialPort_DataReceived
End Function
Private Sub mySerialPort_DataReceived(ByVal sender As Object, ByVal e As SerialDataReceivedEventArgs)
'omitted steps to get the scanned data
ScanData = str.Trim()
RaiseEvent NewScanData(scandata) 'raise the scan event
End sub end class
Public Class frmOrder
Friend WithEvents scanner As New ClsComPort
Private Sub GetScanData(ByVal ScanData As String) Handles scanner.NewScanData
txtOrder.Text = ScanData 'this runs ok, I got the scan data in this field
LaunchTickets() 'App automatically go to next form- ticket form, this seems to cause the event handling issue
End Sub
Private Sub LaunchTickets()
Me.Visible = False
frmTickets.WindowState = FormWindowState.Maximized
frmTickets.ShowDialog()
Me.Visible = True
End Sub
End Class
Public Class frmticket
Friend WithEvents scanner As New ClsComPort
Private Sub GetScanData(ByVal ScanData As String) Handles scanner.NewScanData
txtTicket.Text = ScanData
'not working, just nothing happen, and when back to order form, program crashed
End Sub
End Class
When you make the instance of the frmticket class you are subscribing to your custom event, but that event only fires when the DataReceived event fires and that is not wired up until you call InitializebcrScanner(you did not call it) - which should be a Sub not a Function since you do not return a boolean value or need to. Make an instance of the form not the default instance.
Private Sub LaunchTickets()
Me.Visible = False
Dim ticketsForm As New frmTickets
ticketsForm.WindowState = FormWindowState.Maximized
ticketsForm.ShowDialog()
Me.Visible = True
End Sub
This:
Public Function InitializebcrScanner() As Boolean
AddHandler mySerialPort.DataReceived, AddressOf mySerialPort_DataReceived
End Function
Should be in the constructor:
Sub New()
AddHandler mySerialPort.DataReceived, AddressOf mySerialPort_DataReceived
End Sub

Disable mouse scroll wheel in combobox VB.NET

Does anyone know of a way to disable the mouse scroll wheel when a control such as a combobox or listbox has focus? For my purposes, combobox is all I need the answer for.
I have a combobox set to trigger a SQL query on SelectedIndexChanged, and accidentally scrolling the wheel while the combobox has focus causes about six SQL queries to fire off simultaneously.
I've found a mix response, put this code in the MouseWheel event:
Dim mwe As HandledMouseEventArgs = DirectCast(e, HandledMouseEventArgs)
mwe.Handled = True
That's all. You don't need to create a new class, if you have your project in an advanced state.
The ComboBox control doesn't let you easily override behavior of the MouseWheel event. Add a new class to your project and paste the code shown below. Compile. Drop the new control from the top of the toolbox onto your form.
Friend Class MyComboBox
Inherits ComboBox
Protected Overrides Sub OnMouseWheel(ByVal e As MouseEventArgs)
Dim mwe As HandledMouseEventArgs = DirectCast(e, HandledMouseEventArgs)
mwe.Handled = True
End Sub
End Class
Beware that this also disables the wheel in the dropdown list.
If you subclass the control it's possible (apologies for the C#)
public class NoScrollCombo : ComboBox
{
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
protected override void WndProc(ref Message m)
{
if (m.HWnd != this.Handle)
{
return;
}
if (m.Msg == 0x020A) // WM_MOUSEWHEEL
{
return;
}
base.WndProc(ref m);
}
}
One such option would be to add a handler to the comboBox, and within that comboBox, resolve the situation. I'm not sure how your code is set up, but I'm assuming if you knew when the event was happening, you could set up some kind of conditional to prevent the queries from happening
'''Insert this statement where your form loads
AddHandler comboBoxBeingWatched.MouseWheel, AddressOf buttonHandler
Private Sub buttonHandler(ByVal sender As System.Object, ByVal e As System.EventArgs)
'''Code to stop the event from happening
End Sub
In this way, you'd be able to maintain the user being able to scroll in the comboBox, but also be able to prevent the queries from happening
Combining all the answers on this thread, the best solution if you don't want to create a custom control is to handle the mousewheel event. The below will also allow the list to be scrolled if it is dropped down.
Assuming your combobox is called combobox1:
If Not ComboBox1.DroppedDown Then
Dim mwe As HandledMouseEventArgs = DirectCast(e, HandledMouseEventArgs)
mwe.Handled = True
End If
I had the exact same issue, but found that simply changing the focus of the control after the query executed to another control such as the "Query" button itself worked better than perfect. It also allowed me to still scroll the control until the SelectedIndex actually changed and was only one line of code.
Just put this in the mousewheel event or in a single handler for all the controls this applies to, maybe call it wheelsnubber.
DirectCast(e, HandledMouseEventArgs).Handled = True