Повернутися

🔄 Передача форми в якості параметра в інші форми

Методичка з робочими прикладами на C# (Windows Forms)

📌 Ключова ідея: Форма в C# — це звичайний клас, похідний від System.Windows.Forms.Form. Тому об'єкт форми можна передавати в методи інших форм як параметр, зберігати посилання та використовувати для доступу до публічних членів.

1. Чому передавати форму як параметр?

Існує кілька сценаріїв, коли це корисно:

💡 Важливо: При передачі форми передається саме посилання на об'єкт, тому всі зміни, зроблені через це посилання, впливають на оригінальну форму.
Жива демонстрація: як працює передача форми
Form1 — Головна форма ×
Статус: Form2 закрита
Поточний колір: LightBlue

2. Базовий приклад: передача Form1 в конструктор Form2

Найпростіший спосіб — передати посилання на форму через конструктор дочірньої форми.

📁 Form2.cs (конструктор з параметром)
using System.Windows.Forms;

namespace ПередачаФорми
{
    public partial class Form2 : Form
    {
        // Зберігаємо посилання на головну форму
        private Form1 _mainForm;

        // Конструктор, який приймає посилання на Form1
        public Form2(Form1 mainForm)
        {
            InitializeComponent();
            _mainForm = mainForm;
            
            // Тепер через _mainForm можна звертатись до публічних членів Form1
            this.Text = "Дочірня форма для " + _mainForm.Text;
        }
    }
}
✏️ Form1.cs (створення Form2 з передачею this)
private void btnOpenForm2_Click(object sender, EventArgs e)
{
    // Передаємо поточний екземпляр Form1 (this) в конструктор Form2
    Form2 f2 = new Form2(this);
    f2.Show();
}

3. Розширений приклад: двостороння комунікація

Створимо дві форми, які можуть змінювати колір одна одної через передані посилання.

Повний робочий проект

📁 Program.cs (точка входу)
using System;
using System.Windows.Forms;

namespace ПередачаФорми
{
    internal static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}
📁 Form1.cs (головна форма)
using System;
using System.Drawing;
using System.Windows.Forms;

namespace ПередачаФорми
{
    public partial class Form1 : Form
    {
        private Button btnOpenForm2;
        private Button btnChangeColor;
        private Label lblStatus;
        
        // Посилання на Form2 (якщо вона відкрита)
        private Form2 _form2;

        public Form1()
        {
            InitializeComponent();
            SetupForm();
        }

        private void SetupForm()
        {
            this.Text = "Головна форма";
            this.Size = new Size(400, 300);
            this.StartPosition = FormStartPosition.CenterScreen;
            this.BackColor = Color.LightBlue;

            btnOpenForm2 = new Button
            {
                Text = "Відкрити Form2",
                Location = new Point(120, 50),
                Size = new Size(150, 35)
            };
            btnOpenForm2.Click += BtnOpenForm2_Click;

            btnChangeColor = new Button
            {
                Text = "Змінити колір Form2",
                Location = new Point(120, 100),
                Size = new Size(150, 35),
                Enabled = false // Активується після відкриття Form2
            };
            btnChangeColor.Click += BtnChangeColor_Click;

            lblStatus = new Label
            {
                Text = "Статус: Form2 закрита",
                Location = new Point(120, 150),
                Size = new Size(200, 30)
            };

            this.Controls.AddRange(new Control[] { btnOpenForm2, btnChangeColor, lblStatus });
        }

        private void BtnOpenForm2_Click(object sender, EventArgs e)
        {
            if (_form2 == null || _form2.IsDisposed)
            {
                // Передаємо посилання на поточну форму (this)
                _form2 = new Form2(this);
                _form2.Show();
                _form2.FormClosed += (s, args) => 
                {
                    btnChangeColor.Enabled = false;
                    lblStatus.Text = "Статус: Form2 закрита";
                };
                btnChangeColor.Enabled = true;
                lblStatus.Text = "Статус: Form2 відкрита";
            }
            else
            {
                _form2.Focus();
            }
        }

        private void BtnChangeColor_Click(object sender, EventArgs e)
        {
            if (_form2 != null && !_form2.IsDisposed)
            {
                // Змінюємо колір Form2 через публічний метод
                _form2.ChangeBackColor(Color.Pink);
            }
        }

        // Публічний метод, який може викликати Form2 для зміни кольору Form1
        public void ChangeBackColor(Color color)
        {
            this.BackColor = color;
        }
    }
}
📁 Form2.cs (дочірня форма)
using System;
using System.Drawing;
using System.Windows.Forms;

namespace ПередачаФорми
{
    public partial class Form2 : Form
    {
        // Зберігаємо посилання на головну форму
        private Form1 _mainForm;
        private Button btnChangeMainColor;
        private Label lblInfo;

        // Конструктор отримує посилання на Form1
        public Form2(Form1 mainForm)
        {
            InitializeComponent();
            _mainForm = mainForm;
            SetupForm();
        }

        private void SetupForm()
        {
            this.Text = "Дочірня форма";
            this.Size = new Size(350, 250);
            this.StartPosition = FormStartPosition.CenterScreen;
            this.BackColor = Color.LightGreen;

            lblInfo = new Label
            {
                Text = "Ця форма отримала посилання на Form1",
                Location = new Point(30, 30),
                Size = new Size(250, 40),
                TextAlign = ContentAlignment.MiddleCenter
            };

            btnChangeMainColor = new Button
            {
                Text = "Змінити колір головної форми",
                Location = new Point(70, 100),
                Size = new Size(180, 40)
            };
            btnChangeMainColor.Click += BtnChangeMainColor_Click;

            this.Controls.AddRange(new Control[] { lblInfo, btnChangeMainColor });
        }

        private void BtnChangeMainColor_Click(object sender, EventArgs e)
        {
            // Викликаємо публічний метод головної форми через збережене посилання
            if (_mainForm != null && !_mainForm.IsDisposed)
            {
                _mainForm.ChangeBackColor(Color.Orange);
            }
        }

        // Публічний метод для зміни кольору цієї форми (викликається з Form1)
        public void ChangeBackColor(Color color)
        {
            this.BackColor = color;
        }
    }
}

4. Альтернативний спосіб: передача через властивість

Іноді зручніше створити публічну властивість і встановити її після створення форми.

📁 Form3.cs (передача через властивість)
public partial class Form3 : Form
{
    // Публічна властивість для зберігання посилання на головну форму
    public Form1 MainForm { get; set; }

    public Form3()
    {
        InitializeComponent();
    }

    private void Form3_Load(object sender, EventArgs e)
    {
        if (MainForm != null)
        {
            this.Text = "Підключено до " + MainForm.Text;
        }
    }
}

// У Form1 створення:
// Form3 f3 = new Form3();
// f3.MainForm = this;
// f3.Show();

5. Переваги та недоліки підходу

✅ Переваги

⚠️ Застереження

6. Патерн "Посередник" (Mediator) з передачею форм

Можна створити окремий клас-посередник, який зберігає посилання на всі форми.

📁 FormMediator.cs
using System.Collections.Generic;
using System.Windows.Forms;

namespace ПередачаФорми
{
    // Клас-посередник для керування формами
    public static class FormMediator
    {
        private static List<Form> _forms = new List<Form>();

        public static void Register(Form form)
        {
            if (!_forms.Contains(form))
            {
                _forms.Add(form);
                form.FormClosed += (s, e) => _forms.Remove(form);
            }
        }

        public static void SendMessageToAll(string message)
        {
            foreach (var form in _forms)
            {
                if (form is IMessageReceiver receiver)
                {
                    receiver.ReceiveMessage(message);
                }
            }
        }
    }

    // Інтерфейс для форм, які можуть отримувати повідомлення
    public interface IMessageReceiver
    {
        void ReceiveMessage(string message);
    }
}

7. Покрокова інструкція для лабораторної роботи

  1. 📁 Створіть новий проект Windows Forms
  2. ➕ Додайте другу форму (Form2)
  3. ✏️ У Form2 створіть поле для зберігання посилання на Form1: private Form1 _mainForm;
  4. ✏️ Створіть конструктор Form2, який приймає Form1: public Form2(Form1 mainForm)
  5. ✏️ У Form1 при створенні Form2 передайте this: new Form2(this)
  6. 🔌 Додайте публічні методи в обидві форми для взаємодії
  7. 🔄 Використовуйте збережені посилання для виклику методів
  8. ⚠️ Не забувайте перевіряти !IsDisposed перед використанням
🎯 Практичне завдання: Модифікуйте приклад з кольорами так, щоб:

8. Поширені помилки та їх вирішення

Помилка Рішення
"ObjectDisposedException" Перевіряйте if (form != null && !form.IsDisposed) перед використанням
Форма не бачить публічні методи Переконайтеся, що методи оголошені як public
Циклічні посилання (Form1 знає Form2, Form2 знає Form1) Це нормально, але слідкуйте за витоками пам'яті. Використовуйте слабкі посилання WeakReference у складних випадках.