Search code examples
c#winformstimer

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!


Solution

  • 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.

    screenshot

    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";
    }