اشتراک کنترل بین دو فرم با نخ مجزا

64hadi64

New Member
سلام
من دوتا فرم دارم که هر کدوم با نخ مجزایی اجرا میشن
f1 کنترل هایی داره(button) که میخوام روی f2 هم نمایش داده بشن
مثلا در f1 نوشتم:
کد:
Form2 f2 = new Form2();
var thr = new Thread(() => f2.ShowDialog());
                thr.Start();
چون قصد داشتم f2 از داخل f1 فراخوانی بشه
و بعد داخل f1 اومدم button ها رو داخل flowLayoutPanel1 قرار دادم
حالا قصدم یه همچین چیزی هست :
کد:
f2.Controls.Add(flowLayoutPanel1)

ولی خب نمیشه و ارور میده چون Thread ها مجزا هستن نمیشه کنترل رو اینطوری استفاده کرد
 

the_king

مدیرکل انجمن
سلام
من دوتا فرم دارم که هر کدوم با نخ مجزایی اجرا میشن
f1 کنترل هایی داره(button) که میخوام روی f2 هم نمایش داده بشن
مثلا در f1 نوشتم:
کد:
Form2 f2 = new Form2();
var thr = new Thread(() => f2.ShowDialog());
                thr.Start();
چون قصد داشتم f2 از داخل f1 فراخوانی بشه
و بعد داخل f1 اومدم button ها رو داخل flowLayoutPanel1 قرار دادم
حالا قصدم یه همچین چیزی هست :
کد:
f2.Controls.Add(flowLayoutPanel1)

ولی خب نمیشه و ارور میده چون Thread ها مجزا هستن نمیشه کنترل رو اینطوری استفاده کرد
اساسا بخاطر اینکه کنترل های ویندوز thread safe نیستند همچین کاری به هیچ روشی انجام نمیشه.
و البته یک کنترل صرفا یک Parent داره، یعنی نمیتونه همزمان در دو جای متفاوت نمایش داده بشه.

اشتراک یک کنترل بین دو نخ متفاوت صرفا در حالتی ممکنه که اون کنترل thread safe باشه که کنترل های مرسوم نیستند.
کاری که معمولا انجام می دهند اینه که یا با Invoke به نخ ایجاد کننده اون کنترل ماموریت می دهند که از طرف یک نخ دیگه کاری رو انجام بده یا اینکه همه کنترل ها رو در یک نخ می سازند و در نخ های جانبی صرفا پردازش هایی انجام میشه که کاری با کنترل ها ندارند.
اگه InvokeRequired رو جستجو کنید مثال و توضیحاتش در انجمن هست.

 

64hadi64

New Member
و البته یک کنترل صرفا یک Parent داره، یعنی نمیتونه همزمان در دو جای متفاوت نمایش داده بشه.
ممنون
سرچ میزنم و لینکی که لطف کردید رو نگاه میکنم
اما اگر بخوام فقط پردازش ها و ساخت کنترل ها در f1 و نخ مربوط به اون انجام بشه و نمایش اونها فقط در f2 و نخ مربوطه باشه چی؟امکان پذیر هست؟
یعنی فقط در یک جا نمایش داده بشه
 

the_king

مدیرکل انجمن
ممنون
سرچ میزنم و لینکی که لطف کردید رو نگاه میکنم
اما اگر بخوام فقط پردازش ها و ساخت کنترل ها در f1 و نخ مربوط به اون انجام بشه و نمایش اونها فقط در f2 و نخ مربوطه باشه چی؟امکان پذیر هست؟
یعنی فقط در یک جا نمایش داده بشه
بله. شما می توانید کنترل رو در نخی بسازید و مشخصه هایی مثل رنگ و ابعاد و ... رو مشخص کنید، تا وقتی هم که نمایش اش ندهید پنجره ای برایش ایجاد نمیشه که مدیریتش مساله باشه، اما به محض اینکه در جایی نمایش اش دادید دیگه پنجره اش ساخته شده و نمی توانید به نخ دیگری انتقالش بدهید.
صرفا با a = new Button پنجره ایجاد نمیشه، مادامی هم که Visible نباشه پنجره نداره، تنظیم و تغییر رنگ و ابعاد تا وقتی که پنجره نداره مشکلی نخواهد داشت. اما به محض اینکه این a در یکجا نمایش داده شد یا بخواهید مقدار مشخصه Handle اش رو بخونید دیگه بی پنجره نیست و صاحب پنجره میشه.
از وقتی صاحب پنجره شد هم دیگه نخ مدیریت کننده اش مشخص شده و نمیتونه توسط نخ دیگری مدیریت بشه.
 

64hadi64

New Member
بله. شما می توانید کنترل رو در نخی بسازید و مشخصه هایی مثل رنگ و ابعاد و ... رو مشخص کنید، تا وقتی هم که نمایش اش ندهید پنجره ای برایش ایجاد نمیشه که مدیریتش مساله باشه، اما به محض اینکه در جایی نمایش اش دادید دیگه پنجره اش ساخته شده و نمی توانید به نخ دیگری انتقالش بدهید.
صرفا با a = new Button پنجره ایجاد نمیشه، مادامی هم که Visible نباشه پنجره نداره، تنظیم و تغییر رنگ و ابعاد تا وقتی که پنجره نداره مشکلی نخواهد داشت. اما به محض اینکه این a در یکجا نمایش داده شد یا بخواهید مقدار مشخصه Handle اش رو بخونید دیگه بی پنجره نیست و صاحب پنجره میشه.
از وقتی صاحب پنجره شد هم دیگه نخ مدیریت کننده اش مشخص شده و نمیتونه توسط نخ دیگری مدیریت بشه.
ممنون
ولی من در پست اول همین تاپیک همین کارو کردم
اومدم در f1 کنترل ها رو از جمله button ها و
flowLayoutPanel1
و محاسبات مربوط به اونها رو انجام دادم و بعد زدم
f1. flowLayoutPanel1.Controls.Add(button);
ولی در همون f1 زدم

f2.Controls.Add(flowLayoutPanel1);

ولی خب میگه کنترل های موجود در یک thread رو نمیشه در thread دیگه استفاده کرد

شاید هم من منظور شما رو متوجه نشدم،اگر ممکنه یک مثال بزنید
 

the_king

مدیرکل انجمن
ممنون
ولی من در پست اول همین تاپیک همین کارو کردم
اومدم در f1 کنترل ها رو از جمله button ها و
flowLayoutPanel1
و محاسبات مربوط به اونها رو انجام دادم و بعد زدم
f1. flowLayoutPanel1.Controls.Add(button);
ولی در همون f1 زدم

f2.Controls.Add(flowLayoutPanel1);

ولی خب میگه کنترل های موجود در یک thread رو نمیشه در thread دیگه استفاده کرد

شاید هم من منظور شما رو متوجه نشدم،اگر ممکنه یک مثال بزنید
اون flowLayoutPanel1 رو شما در f1 نمایش داده اید؟ اگر نمایش داده باشید که دیگه نمی توانید در f2 ای که در نخ دیگری مدیریت میشه نمایش اش بدهید.
از طرف دیگه اون f2 اگر در نخ دوم نمایش داده بشه دیگه در نخ اول نه به خود f2 و نه به f2.Controls نباید کاری داشته باشید.
شما وقتی f2 رو ShowDialog کردید دیگه مدیریتش با اون new Thread ئه، نباید در نخ اول کاری به f2 داشته باشید. اگر لازمه در f2 کاری انجام بدهید یا باید f2.Invoke کنید تا در نخ خودش چیزی رو اجرا کنه یا منتظر رخداد هایی مثل f2.Shown باشید که در نخ مدیریت کننده اش رخ میده.
 

64hadi64

New Member
اون flowLayoutPanel1 رو شما در f1 نمایش داده اید؟ اگر نمایش داده باشید که دیگه نمی توانید در f2 ای که در نخ دیگری مدیریت میشه نمایش اش بدهید.
از طرف دیگه اون f2 اگر در نخ دوم نمایش داده بشه دیگه در نخ اول نه به خود f2 و نه به f2.Controls نباید کاری داشته باشید.
شما وقتی f2 رو ShowDialog کردید دیگه مدیریتش با اون new Thread ئه، نباید در نخ اول کاری به f2 داشته باشید. اگر لازمه در f2 کاری انجام بدهید یا باید f2.Invoke کنید تا در نخ خودش چیزی رو اجرا کنه یا منتظر رخداد هایی مثل f2.Shown باشید که در نخ مدیریت کننده اش رخ میده.
نه من دقیقا در f1 فقط button رو Add کردم به flowLayoutPanel1 و در f2 اومدم یک نمونه از f1 ساختم(var _f1 = new Form1();) و بعد در خود f2 نوشتم
کد:
this.Controls.Add(_f1.flowLayoutPanel1);

اگر نامفهوم هست کل پروژه رو اینجا بفرستم
 

the_king

مدیرکل انجمن
نه من دقیقا در f1 فقط button رو Add کردم به flowLayoutPanel1 و در f2 اومدم یک نمونه از f1 ساختم(var _f1 = new Form1();) و بعد در خود f2 نوشتم
کد:
this.Controls.Add(_f1.flowLayoutPanel1);

اگر نامفهوم هست کل پروژه رو اینجا بفرستم
من اطلاعی از ساختار flowLayoutPanel1 ندارم، اما اگر این کنترل در f1 نمایش داده شده باشه یا به هر دلیلی در نخی که ایجاد شده برایش پنجره ساخته شده باشه دیگه نمیتونه در نخی که f2 بکار میبره اون flowLayoutPanel1 رو جایی Add کنه.
 

64hadi64

New Member
من اطلاعی از ساختار flowLayoutPanel1 ندارم، اما اگر این کنترل در f1 نمایش داده شده باشه یا به هر دلیلی در نخی که ایجاد شده برایش پنجره ساخته شده باشه دیگه نمیتونه در نخی که f2 بکار میبره اون flowLayoutPanel1 رو جایی Add کنه.
به هیچ وجه ، flowLayoutPanel1 نه جایی Add شده البته غیر از f2 و نه پنجره براش ساخته شده
ساختارش هم همون ساختار System.Windows.Forms.FlowLayoutPanel هست که ازش
new
گرفته شده
 

the_king

مدیرکل انجمن
به هیچ وجه ، flowLayoutPanel1 نه جایی Add شده البته غیر از f2 و نه پنجره براش ساخته شده
ساختارش هم همون ساختار System.Windows.Forms.FlowLayoutPanel هست که ازش
new
گرفته شده
C#:
using System;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;

namespace FlowLayoutPanelSample
{
    public partial class Form1 : Form
    {
        public static FlowLayoutPanel _flowLayoutPanel1;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            _flowLayoutPanel1 = new FlowLayoutPanel() { Dock = DockStyle.Fill };
            for (var i = 1; i <= 5; i++)
            {
                var button = new Button()
                {
                    Text = @"Test " + i,
                    BackColor = Color.LightBlue,
                    Enabled = ((i % 2) == 1),
                    Size = new Size(80, 30)
                };
                _flowLayoutPanel1.Controls.Add(button);
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            var f2 = new Form2();
            var t = new Thread(() => f2.ShowDialog());
            t.Start();
        }
    }
}

C#:
using System;
using System.Windows.Forms;

namespace FlowLayoutPanelSample
{
    public partial class Form2 : Form
    {
        public Form2()
        {
            InitializeComponent();
        }

        private void Form2_Load(object sender, EventArgs e)
        {
            this.Controls.Add(Form1._flowLayoutPanel1);
        }
    }
}
 

64hadi64

New Member
C#:
using System;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;

namespace FlowLayoutPanelSample
{
    public partial class Form1 : Form
    {
        public static FlowLayoutPanel _flowLayoutPanel1;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            _flowLayoutPanel1 = new FlowLayoutPanel() { Dock = DockStyle.Fill };
            for (var i = 1; i <= 5; i++)
            {
                var button = new Button()
                {
                    Text = @"Test " + i,
                    BackColor = Color.LightBlue,
                    Enabled = ((i % 2) == 1),
                    Size = new Size(80, 30)
                };
                _flowLayoutPanel1.Controls.Add(button);
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            var f2 = new Form2();
            var t = new Thread(() => f2.ShowDialog());
            t.Start();
        }
    }
}

C#:
using System;
using System.Windows.Forms;

namespace FlowLayoutPanelSample
{
    public partial class Form2 : Form
    {
        public Form2()
        {
            InitializeComponent();
        }

        private void Form2_Load(object sender, EventArgs e)
        {
            this.Controls.Add(Form1._flowLayoutPanel1);
        }
    }
}
ممنون
کدتون رو تست کردم
فرم 2 باز میشه اما هیچ کنترلی داخلش نیست
 

the_king

مدیرکل انجمن

پیوست ها

  • FlowLayoutPanelSample.zip
    397 کیلوبایت · بازدیدها: 3

64hadi64

New Member
احتمالا همه رخداد ها رو به متد ها متصل نکرده اید، یکی از اون متد های Load رو از قلم انداخته اید.
FlowLayoutPanelSample.zip
ممنون
بله حق با شما بود
چطور میتونم Thread مربوط به Form2 رو استارت کنم طوری که موقع بسته و باز شدن Form1 همچنان Form2 به کار خودش ادامه بده؟
با توجه به اینکه رخداد ها و Button های مربوطه در Form1 هستند
منظورم اینه که مثلا اگر Form1 ما طوری طراحی شده باشه که نیاز باشه بسته و باز بشه(به صورت خودکار) ، چطور Form2 رو طوری باز نگه داریم که موقع دوباره باز شدن(و آپدیت شدن کنترل های Form1 ) فرم 2 هم فقط آپدیت بشه
من یه کد نوشتم ولی فقط میتونه فرم 2 رو باز نگه داره اما پیغام خطا میده چون Thread مربوط به Form2 در Form1 استارت شده نمیتونم از کد استفاده کنم
کد رو میفرستم

کد:
 btn.Click += (x, y) =>
            {
                Form2 f2 = new Form2();

                var forms1 = new List<Form>();
                foreach (Form f in System.Windows.Forms.Application.OpenForms)
                {
                    if (f is Form2)
                    {
                        forms1.Add(f);
                    }
                }
                if (forms1.Count == 0)
                {

                    var thr = new Thread(() => f2.ShowDialog());
                        thr.Start();
                }
            };
 

the_king

مدیرکل انجمن
ممنون
بله حق با شما بود
چطور میتونم Thread مربوط به Form2 رو استارت کنم طوری که موقع بسته و باز شدن Form1 همچنان Form2 به کار خودش ادامه بده؟
با توجه به اینکه رخداد ها و Button های مربوطه در Form1 هستند
منظورم اینه که مثلا اگر Form1 ما طوری طراحی شده باشه که نیاز باشه بسته و باز بشه(به صورت خودکار) ، چطور Form2 رو طوری باز نگه داریم که موقع دوباره باز شدن(و آپدیت شدن کنترل های Form1 ) فرم 2 هم فقط آپدیت بشه
من یه کد نوشتم ولی فقط میتونه فرم 2 رو باز نگه داره اما پیغام خطا میده چون Thread مربوط به Form2 در Form1 استارت شده نمیتونم از کد استفاده کنم
کد رو میفرستم

کد:
 btn.Click += (x, y) =>
            {
                Form2 f2 = new Form2();

                var forms1 = new List<Form>();
                foreach (Form f in System.Windows.Forms.Application.OpenForms)
                {
                    if (f is Form2)
                    {
                        forms1.Add(f);
                    }
                }
                if (forms1.Count == 0)
                {

                    var thr = new Thread(() => f2.ShowDialog());
                        thr.Start();
                }
            };
اینطوری هم می توانید وجود Form2 رو بررسی کنید :
C#:
            var f2 = (Form2)Application.OpenForms["Form2"];
            if (f2 == null)
            {
                f2 = new Form2();
                var thr = new Thread(() => f2.ShowDialog());
                thr.Start();
            }
در Form1 تون رخداد Shown هست که موقع نمایش Form1 رخ میده، می توانید وصلش کنید به یک متد در کلاس Form1 که با Invoke در نخی که Form2 رو مدیریت می کنه یک متد دلخواه شما رو اجرا کنه و آپدیت کردن هر چی که هست انجام بده.
اون Invoke باعث میشه که YourUpdateProc بجای نخ مدیریت کننده Form1 با نخ مدیریت کننده Form2 اجرا بشه :
C#:
        private void Form1_Shown(object sender, EventArgs e)
        {
            var f2 = (Form2)Application.OpenForms["Form2"];
            f2?.Invoke(new ThreadStart(f2.YourUpdateProc));
        }

C#:
    public partial class Form2 : Form
    {
        public Form2()
        {
            InitializeComponent();
        }

        private void Form2_Load(object sender, EventArgs e)
        {
            this.Controls.Add(Form1._flowLayoutPanel1);
        }

        public void YourUpdateProc()
        {
        }
    }
 

the_king

مدیرکل انجمن
ممنون
به این خط اشکال میگیره ، تصویر خطا رو براتون میفرستم
مشاهده پیوست 113822
نسخه زبان #C تون قدیمی است، برای همین .? رو نمیشناسه، بجای f2?.Invoke می توانید از if (f2 != null) f2.Invoke استفاده کنید.

این رو هم وقتی جایگزین کردم علاوه بر باز بودن فرم 2 ،باز هم اون رو باز میکرد و شروع میکرد به خطا دادن
احتمالا Name فرم دوم تون چیزی بجز اون "Form2" ئه. من ممکنه یک فرم با اسم فایل کلاس Form2.cs داشته باشم ولی در پنجره Properties مشخصه Name یک نام دیگری بجز Form2 داشته باشه یا در کد برنامه Name دیگری برایش انتخاب کنم.
 

جدیدترین ارسال ها

بالا