SqlDependency onchange event infinite loop - c#

I have a simple query, and the event fires at the correct time. However, once fired, the property, .HasChanges, of the SqlDependency object is always set as true.
The first time OnChange is fired, the SqlNotificationEventArgs Info property is "Inserted". The second time the event is fired it's "Already Changed".
I commented all of my code in the OnChange event out to verify that my code wasn't causing the change.
Servicebroker is enabled in the database
Is there a reason the following code causes an infinite loop of onChange events?
static void Main()
{
SqlDependency.Stop(Properties.Settings.Default.DEVConnectionString);
SqlDependency.Start(Properties.Settings.Default.DEVConnectionString);
using (SqlConnection cn = new SqlConnection(Properties.Settings.Default.DEVConnectionString))
{
cn.Open();
using (SqlCommand cmd = new SqlCommand("SELECT UserPageActionLogID, PageActionID FROM dbo.UserPageActionLog WHERE PageActionID != 3 ORDER BY UserPageActionLogID ASC", cn))
{
cmd.Notification = null;
SqlDependency dep = new SqlDependency(cmd);
dep.OnChange += dep_onchange;
using (SqlDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
//Do nothing on first run
}
}
}
}
Application.Run(); //Prevents the application from closing
}
private static void dep_onchange(object sender, SqlNotificationEventArgs e)
{
SqlDependency dependency = sender as SqlDependency;
dependency.OnChange -= dep_onchange;
//Do stuff for the function. I commented this out and still had an issue
//Resubscribe to the event to continue catching future changes
dependency.OnChange += dep_onchange;
}

It appears that the both the OnChange handler and the SqlDependency instance are only good for ONE event. After the event is fired and you unsubscribe the handler, you need to register your handler to a NEW SqlDependency object.
Please see the link here for full details: http://msdn.microsoft.com/en-us/library/a52dhwx7(v=vs.80).aspx

Here is how I handled it...
public class ClientClass
{
public ClientClass()
{
var watchForChange = new WatchForChange(connectionString);
watchForChange.TableChanged += WatchForChange_TableChanged;
watchForChange.StartWatching();
}
private void WatchForChange_TableChanged(object sender, EventArgs e)
{
// Some COde
}
}
public class WatchForChange
{
// Should implement IDisposable
private string _connectionString;
private SqlDependency _sqlWatcher;
public WatchForChange(string connectionString)
{
_connectionString = connectionString;
}
public void StartWatching()
{
using (var sqlConnection = new SqlConnection(_connectionString))
{
sqlConnection.Open();
using var sqlCommand = new SqlCommand("select somefield from dbo.sometable", sqlConnection);
{
SqlDependency.Start(_connectionString);
_sqlWatcher = new SqlDependency(sqlCommand);
_sqlWatcher.OnChange += _sqlWatcher_OnChange;
}
// Notifies SQL Server that something is listening for changes to this table
using var sqlDataReader = sqlCommand.ExecuteReader();
}
}
private void _sqlWatcher_OnChange(object sender, SqlNotificationEventArgs e)
{
// Unsubscribe and set to null
_sqlWatcher.OnChange -= _sqlWatcher_OnChange;
_sqlWatcher = null;
SqlNotificationInfo sqlNotificationInfo = e.Info;
// Raise the event on Inserts and Updates
if (sqlNotificationInfo.Equals(SqlNotificationInfo.Insert) || sqlNotificationInfo.Equals(SqlNotificationInfo.Update))
{
OnTableChanged(e);
}
// Create a new instance of _sqlWatcher (SqlDependency)
StartWatching();
}
protected virtual void OnTableChanged(EventArgs e)
{
TableChanged?.Invoke(this, e);
}
public event EventHandler TableChanged;
}

Related

how to call timer in UC Control in Form Main?

Timer1 not start when add new User Control.I have 1 User Control (UC_Machine).And when load Form Main I using timer execute SQL query in query variable to get data from table [tbl_FF_Trigger]
I have 1 User Control (UC_Machine).And when load Form Main I using timer execute SQL query in query variable to get data from table [tbl_FF_Trigger]
-Code in UC_Machine:
private void UC_Machine_Load(object sender, EventArgs e)
{
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
string query = "SELECT CRDName, PartNumber ,DefectName FROM [tbl_FF_Trigger] where Machine = '" + Machine + "'";
db.fillDataGridView(query, dataGridView1);
dataGridView1.BackgroundColor = Color.White;
dataGridView1.RowHeadersVisible = false;
dataGridView1.Update();
dataGridView1.Refresh();
}
Code in form MAIN. Will get the information of the machines from the function Machine_Infor.GetMachine_Infors(). It will then create a UC_Machine array from that information. If the machine in the array does not already exist in the panellayout, it will be added to the panellayout.
In addition, it also checks if the machine exists in the tbl_FF_Trigger table. Otherwise it will delete the machine from the panellayout.
private void Main_Load(object sender, EventArgs e)
{
Get_Infor();
}
private void Get_Infor()
{
System.Timers.Timer timer = new System.Timers.Timer();
timer.Interval = 3000; // Thời gian chạy (5000 milliseconds = 5 second)
timer.Elapsed += Timer_Elapsed;
timer.Start();
}
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
// Add new item to panellayout if machine have falsecall
var data = Machine_Infor.GetMachine_Infors();
var list = new UC_Machine[data.Count];
int i = 0;
itemFoods = new List<UC_Machine>();
itemFoodsFilter = new List<UC_Machine>();
HashSet<string> existingMachine = new HashSet<string>();
foreach (var item in data)
{
if (!existingMachine.Contains(item.Machine))
{
bool isExisting = false;
foreach (UC_Machine uc in myFlowLayoutPanel1.Controls)
{
if (uc.Machine == item.Machine)
{
isExisting = true;
break;
}
}
if (!isExisting)
{
list[i] = new UC_Machine();
list[i].CRDName = item.CRDName;
list[i].Model = item.Model;
list[i].Machine = item.Machine;
list[i].PartNumber = item.PartNumber;
list[i].Workcell = item.Workcell;
list[i].CRDName = item.CRDName;
list[i].Date = item.Date;
itemFoods.Add(list[i]);
itemFoodsFilter.Add(list[i]);
existingMachine.Add(item.Machine);
i++;
}
}
}
if (myFlowLayoutPanel1.InvokeRequired)
{
myFlowLayoutPanel1.Invoke((MethodInvoker)delegate
{
myFlowLayoutPanel1.Controls.AddRange(list.Where(x => x != null).ToArray());
});
}
else
{
myFlowLayoutPanel1.Controls.AddRange(list.Where(x => x != null).ToArray());
}
// Remove machine if Falsecall not found
string maincon = ConfigurationManager.ConnectionStrings["Connstring"].ConnectionString;
// Connect to the SQL Server database and execute the query to check for the existence of "vnhcmsleaoi05" in the "tbl_FF_Trigger" table.
using (SqlConnection connection = new SqlConnection(maincon))
{
connection.Open();
foreach (UC_Machine uc in myFlowLayoutPanel1.Controls)
{
string query = "SELECT COUNT(*) FROM tbl_FF_Trigger WHERE Machine = '"+ uc.Machine+"'";
using (SqlCommand command = new SqlCommand(query, connection))
{
int count = (int)command.ExecuteScalar();
if (count == 0)
{
if (myFlowLayoutPanel1.InvokeRequired)
{
myFlowLayoutPanel1.Invoke((MethodInvoker)delegate
{
myFlowLayoutPanel1.Controls.Remove(uc);
itemFoods.Remove(uc);
uc.Dispose();
});
}
else
{
myFlowLayoutPanel1.Controls.Remove(uc);
itemFoods.Remove(uc);
uc.Dispose();
}
break;
}
}
}
}
}
Code working OK when load Form. when tbl_FF_Trigger add new value myFlowLayoutPanel1 new UC_Machine
but timer1 not start. I know this because the datagirdview has no data in the newly added UC_Machine.I want when myFlowLayoutPanel1 adds 1 UC_Machine, timer1 will start
Anyone have any advise or solution for this case, please help me. Thanks a lot!
Your question is how to call timer in UC Control in Form Main. The main form is trying to GetInfo from the UC but consider that this might be "backwards" and that the UC Control should be notifying Form Main when it gets the new info instead. Here's what I mean:
Your UC has its own timer1 (we'll get timer1 started don't worry). What main form needs is to be notified when a new query is available in one of the UCs. Giving main form its own timer will interfere with an otherwise-orderly process. Consider making an event in your UC as shown and fire it whenever UC is done getting a new query.
UserControlMachine
Example: UC starts its own timer1 and fires RecordsChanged event when new query completes.
public partial class UserControlMachine : UserControl
{
public UserControlMachine()=>InitializeComponent();
public BindingList<Record> Records { get; } = new BindingList<Record>();
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
timer1 = new Timer { Interval = 2500 };
timer1.Tick += onTimer1Tick;
timer1.Start();
dataGridView1.DataSource = Records;
Records.Add(new Record()); // <- Auto-generate columns
dataGridView1.Columns[nameof(Record.DefectName)].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
}
private System.Windows.Forms.Timer timer1;
private void onTimer1Tick(object sender, EventArgs e) => queryDB();
private void queryDB()
{
// S I M U L A T E D Q U E R Y R E S U L T
Records.Clear();
for (int i = 0; i < Rando4Test.Next(1,5); i++)
{
Records.Add(new Record
{
CRDName = $"CRD-{(char)Rando4Test.Next(65,70)}{Rando4Test.Next(100, 200)}"
});
}
// Notify the Main Form that something has changed.
RecordsChanged?.Invoke(this, EventArgs.Empty);
}
public event EventHandler RecordsChanged;
// For testing purposes
public static Random Rando4Test { get; } = new Random();
}
Main Form
All the main form has to do is listen for RecordsChanged events.
public partial class Form1 : Form
{
public Form1() => InitializeComponent();
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
// Simulation: Add 2 machines
for (int i = 0; i < 2; i++)
{
var machine = new UserControlMachine
{
Size = new Size(myFlowLayoutPanel1.Width - SystemInformation.VerticalScrollBarWidth, 200),
BorderStyle = BorderStyle.FixedSingle,
};
myFlowLayoutPanel1.Controls.Add(machine);
// Listen for new query results
machine.RecordsChanged += onAnyUCRecordsChanged;
}
}
private void onAnyUCRecordsChanged(object sender, EventArgs e)
{
int totalDefects = 0;
foreach (var machine in myFlowLayoutPanel1.Controls.OfType<UserControlMachine>())
{
totalDefects += machine.Records.Count;
}
Text = $"Main Form - Total Defects: {totalDefects}";
}
}
WHERE Record class represents a DataGridViewRow
public class Record
{
public string PartNumber { get; set; } =
Guid.NewGuid().ToString().Substring(0, 13).ToUpper();
public string CRDName { get; set; }
public string DefectName { get; set; } = "Unknown Error";
}

Are there any ways to refresh a listview every 5 or 3 seconds without using the timer?

I have a form which is running on the other laptop, this is the kitchen side where all the orders will go through after buying in my POS (which is running on the other laptop also) side.
Now my listview in the kitchen side refreshes after 5 seconds 'using the timer', are there any options or ways to refresh the listview without using the timer so that the 'Focus' when I select an item inside the listview will not disappear?
This is the my code:
public Kitchen()
{
InitializeComponent();
listView2.Columns.Add("ORDERS", 800);
listView2.View = View.Details;
System.Windows.Forms.Timer timer_1 = new System.Windows.Forms.Timer();
timer1.Interval = 5000;
timer1.Tick += new System.EventHandler(timer1_Tick);
timer1.Start();
}
private void dinein(String tblnmber)
{
String[] row = { tblnmber };
listView2.Items.Add(new ListViewItem(row));
}
public void loaddinein()
{
listView2.Items.Clear();
string sq = "select tblnmber as [ORDERS] FROM Kitchen Group By tblnmber";
cmd = new SqlCommand(sq,con);
try
{
con.Open();
adp = new SqlDataAdapter(cmd);
adp.Fill(dt);
foreach (DataRow row in dt.Rows)
{
dinein(row[0].ToString());
}
con.Close();
dt.Rows.Clear();
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
con.Close();
}
}
private void timer1_Tick(object sender, EventArgs e)
{
loaddinein();
}
Well your question is really how do I refresh an existing list of items without changing order or focus? not anything to do with timers.
To accomplish that when you fetch the data from the DB again, you need to determine which items have changed in the list (compare the text of your model to an item in the list) and simply update the Text of those items. Overwriting a ListViewItem's Text property won't change selection/focus or re-ordering by default.
Don't clear out the ListView and repopulate otherwise focus/selection will change.
A timer is still perfectly valid to use.
Pooling continuously to the DB server is not a good approach, you can go for either of the two approaches.
Raise a change message using trigger to MSMQ, and subscribe to the
MSMQ for new messages. For more details on the implementation you
can check here
Monitoring the data changes using SqlDependency, for more details you can check here
Note: Both the approaches have it own pro/cons. For example if the number of listeners are more, in that case SQL Dependency will hit the performance.
Hi guys i've already watch and read some tutorials , and implement it, unfortunately sql dependency is not firing to my datagridview nor listview. I've also enabled the broker.
This is the code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;
//ALTER DATABASE HOB SET ENABLE BROKER
namespace DemoSQL
{
public partial class Form1 : Form
{
public string m_connect = #"Data Source=DESKTOP-3B561M1;Initial Catalog=Users;Integrated Security=True";
SqlConnection con = null;
public delegate void NewHome();
public event NewHome OnNewHome;
public Form1()
{
InitializeComponent();
try
{
SqlClientPermission ss = new SqlClientPermission(System.Security.Permissions.PermissionState.Unrestricted);
ss.Demand();
}
catch (Exception)
{
throw;
}
SqlDependency.Stop(m_connect);
SqlDependency.Start(m_connect);
con = new SqlConnection(m_connect);
}
private void Form1_Load(object sender, EventArgs e)
{
OnNewHome+=new NewHome(Form1_OnNewHome);//tab
//load data vao datagrid
LoadData();
}
public void Form1_OnNewHome()
{
ISynchronizeInvoke i = (ISynchronizeInvoke)this;
if (i.InvokeRequired)//tab
{
NewHome dd = new NewHome(Form1_OnNewHome);
i.BeginInvoke(dd, null);
return;
}
LoadData();
}
//Ham load data
void LoadData()
{
DataTable dt = new DataTable();
if (con.State==ConnectionState.Closed)
{
con.Open();
}
SqlCommand cmd = new SqlCommand("SELECT FirstName,LastName from dbo.Uss", con);
cmd.Notification = null;
SqlDependency de = new SqlDependency(cmd);
de.OnChange += new OnChangeEventHandler(de_OnChange);
dt.Load(cmd.ExecuteReader(CommandBehavior.CloseConnection));
dataGridView1.DataSource = dt;
}
public void de_OnChange(object sender, SqlNotificationEventArgs e)
{
SqlDependency de = sender as SqlDependency;
de.OnChange -= de_OnChange;
if (OnNewHome!=null)
{
OnNewHome();
}
}
}
}

TabPage freezing application

I have a TabControl, with a few TabPages. What I am trying to do is change tabs, and have it call a richtextbox on a different tab. I will try to word the question better after code...
void tabControl1_SelectedIndexChanged(object sender, System.EventArgs e)
{
switch(tabControl1.SelectedTab.Name)
{
case "tabPage_ProdOrders":
dostuff();
break;
}
//throw new System.NotImplementedException();
}
void dostuff()
{
while (tabControl1.SelectedTab == tabControl1.TabPages["tabPage_ProdOrders"])
{
safeCall("testing...\n");
Thread.Sleep(10000);
}
}
delegate void SetTextCall(string s);
public void safeCall(string s)
{
if (this.richTextBox1.InvokeRequired)
{
SetTextCall d = new SetTextCall(safeCall);
this.Invoke(d, new object[] { s });
}
else this.richTextBox1.AppendText(string.Format(":{0}:\n",s));
}
I know it looks sloppy- sorry. So the richtextbox resides on tabpage "tabPage_DEV". What I am trying to have happen is when I change to tabpage "tabPage_ProdOrders" have it append text to the richtextbox that is on "tabPage_DEV". This is moreover a test to make sure everything runs smooth, what I eventually will have happening is once "tabPage_ProdOrders" is selected I will have a gridview bound to my database, and so long as that page is selected, it will refresh from the database every X seconds. The problem is that as soon as I select the "tabPage_ProdOrders" the whole app freezes. I am assuming this is due to the Thread.Sleep() that I have within the while loop (my assumption is that since that void is part of the windows from that when it is .Sleep() the whole form is .Sleep() correct? Any guidance on a work around would be stellar.
Add a Timer to your form and code its Tick event to do all the DB stuff.
Change the dostuff method like this:
void dostuff()
{
if (tabControl1.SelectedTab == tabControl1.TabPages["tabPage_ProdOrders"])
{
dbTimer.Interval = 10000; // your interval in ms
dbTimer.Start();
}
else dbTimer.Stop();
}
With Thread.Sleep(..) you send the current, that is the GUI thread to sleep. Suerely not what you want..
I used similar to TaW's suggestions...
delegate void populateProdOrders(DataTable dt);
public void safePopulate(DataTable dt)
{
if (this.dataGridView2.InvokeRequired)
{
populateProdOrders d = new populateProdOrders(safePopulate);
this.Invoke(d, new object[] { dt });
}
else this.dataGridView2.DataSource = dt;
}
public Form1()
{
// stuff
System.Timers.Timer refreshProdOrders = new System.Timers.Timer(5000);
refreshProdOrders.Elapsed += refreshProdOrders_Elapsed;
refreshProdOrders.AutoReset = true;
refreshProdOrders.Enabled = true;
}
void refreshProdOrders_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
//dostuff();
var globes = SharedResourceVariables.globals;
DataTable dt = new DataTable();
System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(globes.SQLConn);
using (conn)
{
System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("development_usp_viewProdductionOrders", conn);
cmd.CommandType = CommandType.StoredProcedure;
using (cmd)
{
conn.Open();
System.Data.SqlClient.SqlDataReader dr = cmd.ExecuteReader();
dt.Load(dr);
conn.Close();
}
}
safePopulate(dt);
}

associate button with enter key

i got a WinForm Project in C# 4.0.
i want to when the user click the button enter then it call onclick event of this button.
my code:
public XtraForm_Main()
{
InitializeComponent();
...
this.AcceptButton = (Button)this.Controls["button_Valider"];
}
private void Main_Load(object sender, EventArgs e)
{
this.AcceptButton = (Button)this.Controls["button_Valider"];
}
private void button_Valider_Click(object sender, EventArgs e)
{
try
{
using (var connectionWrapper = new Connexion())
{
var connectedConnection = connectionWrapper.GetConnected();
string SqlSyntax = "SELECT * FROM ORDRE WHERE REF_EXPED = #REFERENCE";
SqlCommand comm_InsUpt = new SqlCommand(SqlSyntax, connectionWrapper.conn);
comm_InsUpt.Parameters.AddWithValue("#REFERENCE", textEdit_ref.Text);
SqlDataAdapter adapt_SelectAll = new SqlDataAdapter();
adapt_SelectAll.SelectCommand = comm_InsUpt;
DataSet dSet_SelectAll = new DataSet();
adapt_SelectAll.Fill(dSet_SelectAll, "BON_ETIKET");
var xtraReport_Pricipal = new Zebra_Web();
xtraReport_Pricipal.Parameters["Count_Ordre"].Value = 1;
xtraReport_Pricipal.Parameters["IdPacket"].Value = 1;
xtraReport_Pricipal.DataSource = dSet_SelectAll;
xtraReport_Pricipal.DataMember = dSet_SelectAll.Tables[0].TableName;
xtraReport_Pricipal.CreateDocument();
xtraReport_Pricipal.PrintingSystem.ShowMarginsWarning = false;
xtraReport_Pricipal.PrintingSystem.ContinuousPageNumbering = true;
//xtraReport_Pricipal.ShowPreviewDialog();
xtraReport_Pricipal.Print(Properties.Settings.Default.Zebra);
dSet_SelectAll.Dispose();
adapt_SelectAll.Dispose();
}
}
catch (Exception excThrown)
{
throw new Exception(excThrown.Message, excThrown);
}
}
i have tried to put this line:
this.AcceptButton = (Button)this.Controls["button_Valider"];
in constructor and onLoad From event but still not work.
when the user click the button it nothing happen. i have to clic it with the mouse.
You need to set KeyPreview Property of your Form to True.
and then write a KeyDown Event to Handle Enter Key on Form
as Below:
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
button_Valider_Click(sender,e);
}
}

C# Windows Forms, Combobox MouseClick event getting fired multiple times

I have a windows form with many controls. A tiny part of it is logging in to an SQL server and fetching the list of database names and assigning the collection to a combobox.
private void InitializeComponent()
{
//...
//...
this.ServerTB = new System.Windows.Forms.TextBox();
this.UserNameTB = new System.Windows.Forms.TextBox();
this.PasswordTB = new System.Windows.Forms.TextBox();
//...
//...
this.ServerTB.TextChanged += new System.EventHandler(this.OnSQLServerChanged);
this.UserNameTB.TextChanged += new System.EventHandler(this.OnSQLServerChanged);
this.PasswordTB.TextChanged += new System.EventHandler(this.OnSQLServerChanged);
this.DatabaseCmbBox = new System.Windows.Forms.ComboBox();
//...
//...
this.DatabaseCmbBox.MouseClick += new System.Windows.Forms.MouseEventHandler(this.DatabaseCmbBox_Click);
//....
}
private void DatabaseCmbBox_Click(object sender, MouseEventArgs e)
{
MessageBox.Show(sender.GetType().ToString());
this.Cursor = Cursors.IBeam;
List<string> dbList = new List<string>();
dbList = GetDatabaseList();
DatabaseCmbBox.DataSource = dbList;
DatabaseCmbBox.SelectedIndex = -1;
if (dbList.Count > 0)
{
DatabaseCmbBox.MouseClick -= DatabaseCmbBox_Click;
}
DatabaseCmbBox.Focus();
this.Cursor = Cursors.Default;
}
protected List<string> GetDatabaseList()
{
List<string> list = new List<string>();
string conString = "server=" + ServerTB.Text + ";uid=" + UserNameTB.Text + ";pwd=" + PasswordTB.Text + "; database=master";
try
{
using (SqlConnection con = new SqlConnection(conString))
{
con.Open();
using (SqlCommand cmd = new SqlCommand("select name from sys.databases where name not in ('master', 'model', 'tempdb', 'msdb') ", con))
{
using (IDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
list.Add(dr[0].ToString());
}
dr.Close();
}
cmd.Dispose();
}
con.Close();
}
}
catch(SqlException ex)
{
DatabaseCmbBox.MouseClick -= DatabaseCmbBox_Click;
MessageBox.Show(ex.Message);
ServerTB.Focus();
}
return list;
}
private void OnSQLServerChanged(object sender, EventArgs e)
{
DatabaseCmbBox.MouseClick += DatabaseCmbBox_Click;
}
I don't have a problem in fetching the list of Databases. It takes about 10 seconds to do so. With the messagebox in the event handler, I found out that the MouseClick event, for no apparent reason, gets fired like 38 times. The same thing happens even if I use the Enter event or Click event, instead of the MouseClick event.
Why does this happen, and how does one go about using these kind of events?
Thanks in advance,
RPS.
If you want to get list of Databases, why don't you do so on Combobox value changed event?
Anyways,I see that you are doing
private void OnSQLServerChanged(object sender, EventArgs e)
{
DatabaseCmbBox.MouseClick += DatabaseCmbBox_Click;
}
This should solve your problem
private void OnSQLServerChanged(object sender, EventArgs e)
{
DatabaseCmbBox.MouseClick -= DatabaseCmbBox_Click;
DatabaseCmbBox.MouseClick += DatabaseCmbBox_Click;
}
This is a potential error: you should subscribe DatabaseCmbBox.MouseClick only once, not every time OnSQLServerChanged. Correct your code correspondingly, and the issue with multiple click events will be fixed:
private void OnSQLServerChanged(object sender, EventArgs e)
{
DatabaseCmbBox.MouseClick += DatabaseCmbBox_Click;
}

Categories

Resources