PDA

View Full Version : نسبت دادن Event به کنترل های ساخته شده در Runtime



va2012
چهارشنبه 03 خرداد 1391, 20:58 عصر
سلام دوستان:

چند تا سوال :

1 - من دارم یک برنامه می نویسم که با هر بار کلیک روی یک Button یک دیتاگرید روی فرم ایجاد میکنه و اطلاعات یک تیبل از دیتابیس رو نمایش میده اما حالا می خوام روی هر ردیف از هر کدوم ازاین دیتاگرید هایی که تولید میشن کلیک شد اطلاعات اون ردیف داخل یک سری تکست باکس نمایش داده بشن .

برای این کار از کد زیر استفاده میکنم : (ابتدای کدها یک متغیر از نوع دیتابیس تعریف کردم )

DataGridView dataGridView = new DataGridView();

private void dataGridView_CellClick(object sender, GridViewCellEventArgs e)
{
textBox3.Text = dataGridView.CurrentRow.Cells[2].Value.ToString();
textBox4.Text = dataGridView.CurrentRow.Cells[3].Value.ToString();
textBox5.Text = dataGridView.CurrentRow.Cells[4].Value.ToString();
textBox6.Text = dataGridView.CurrentRow.Cells[5].Value.ToString();
textBox7.Text = dataGridView.CurrentRow.Cells[6].Value.ToString();
textBox8.Text = dataGridView.CurrentRow.Cells[7].Value.ToString();
textBox10.Text = dataGridView.CurrentRow.Cells[9].Value.ToString();
}

و داخل Load فرم هم هنگام ایجاد دیتاگرید ها از این کد استفاده می کنم :

dataGridView.CellClick += new GridViewCellEventHandler(dataGridView_CellClick);

اما این ارور رو میده :

Object reference not set to an instance of an object.

2- سوال دوم اینکه کنترل هایی که زمان اجرا ساخته میشن رو چطور میشه ذخیره کرد که مجبور نباشیم دوباره هنگام لود همشون رو از اول بسازیم؟ مثلا همین برنامه ای که گفتم اگر چند تا دیتاگرید رو کاربر ایجاد کرد باید دوباره هنگام لود فرم همه رو از اول با یک حلقه بسازم و دوباره اطلاعات دیتابیس رو داخل هر کدوم لود کنم. این کار رو درست انجام دادم ولی خوب لود برنامه رو به مرور سنگین میکنه. کسی راه حل بهتری سراغ نداره ؟

3- کد Maximize و Minimize کردن فرم رو میخوام که برای دو تا دکمه قرار بدم و همچنین مخفی کردن تمام دکمه های کنترل باکس طوری که قاب فرم قابل نمایش باشه (البته فرم بدون نوشته هست).

مرسی !

Mahmoud Zaad
چهارشنبه 03 خرداد 1391, 21:29 عصر
سلام
میشه بگید این همه دیتاگریدویو میخواید چکار؟ کلاً توضیح بدید می خواید چکار کنید شاید راه بهتری هم وجود داشته باشه.

va2012
چهارشنبه 03 خرداد 1391, 22:15 عصر
همونطور که بالا توضیح دادم این نرم افزار به این صورت هست که برای هر بخش ابتدا یک تیبل داخل دیتابیس ایجاد می کنم و بعد یک دیتا گرید که اطلاعات اون تیبل رو داخل گرید نمایش میدم. یعنی به ازای هر بخشی که ایجاد میشه یک تیبل در دیتابیس میسازم و یک دیتاگرید مجزا برای ثبت و نمایش اطلاعات مربوط به همون تیبل. البته تعداد جدول ها محدودیت داره.

البته می تونستم اول کار همه بخش ها رو درست کنم و جدول ها رو هم داخل دیتابیس بسازم ولی چون تعداد این بخش ها متغیر هست برای اینکه حجم نرم افزار بالا نره این کار رو انجام دادم.

من میخوام بدونم کنترل های زمان اجرا رو چطور بایستی ذخیره کرد و چطور براشون رویداد نوشت؟ البته خصوصیاتشون رو با XML ذخیره می کنم ولی میخوام بدونم روشی هست که مجبور به ساخت مجدد کنترل نباشیم؟

حالا نه فقط واسه این نرم افزار - فرض کنید نرم افزار ما حین اجرا چند تا کنترل رو ایجاد کنه که لازم هست روی فرم باقی بمونن . بهترین راه واسه ذخیره همه این کنترلها چیه؟

Mahmoud Zaad
پنج شنبه 04 خرداد 1391, 09:46 صبح
خب همونطور که گفتید شما باید تک تک خاصیت هایی رو که در کنترل های مورد نظر تغییر میکنند رو ذخیره کنید. فرض کنید یه باتن به فرم اضافه می کنید باید اندازه(Size)، محل قرار گیری(Location)، متن (Text)، رنگ (Back Color و For Color) و ... در یک فایل یا دیتابیس ذخیره کنید بعد موقع لود فرم اونها رو فراخوانی کنید.

va2012
پنج شنبه 04 خرداد 1391, 12:47 عصر
مرسی . خوب اینا که فرمودین درست ولی با این کار ها هنوز باید کنترل از ابتدا ساخته بشه و بعد از طریق XML یا دیتابیس خصوصیات کنترل ها بازگردانده بشه. ولی منظور من این بود که آیا روشی هست که کنترل های ساخته شده به صورت کامل در قالب همون کنترل به صورت یک سمپل در یک پوشه ذخیره بشن و بعد هنگام اجرای مجدد برنامه از همون پوشه لود بشن.( شبیه کنترل های که در اتوران سازها به صورت template هست). خوب ظاهرا نمیشه . مثل اینکه راه بهتری نیست.

حالا لطفا در مورد سوال اول اگه راهنمایی دارین بفرمایید.

va2012
پنج شنبه 04 خرداد 1391, 19:07 عصر
از دوستان کسی می تونه در مورد Event دیتاگرید ها که توی پست اول گفتم راهنمایی کنه؟

va2012
سه شنبه 09 خرداد 1391, 12:36 عصر
کسی نیست جواب سوال منو بده؟

mahdi87_gh
سه شنبه 09 خرداد 1391, 18:06 عصر
ابتدا بررسی کنید که CurrentRow برابر null نباشد

if(null!=dataGridView1.CurrentRow)

Mahyar.FF
سه شنبه 09 خرداد 1391, 18:22 عصر
1 - اگر exception مربوطه در داخل dataGridView_CellClick رخ میده، پس حتما یکی از سلولهای ردیف کلیک شده، مقدارش null هست. اگر اینطور که گفتم باشه، شما باید کد رو بصورت زیر بنویسید:


private void dataGridView_CellClick(object sender, GridViewCellEventArgs e)
{
textBox3.Text = dataGridView.CurrentRow.Cells[2].Value == null ? "" : dataGridView.CurrentRow.Cells[2].Value.ToString();
textBox4.Text = dataGridView.CurrentRow.Cells[3].Value == null ? "" : dataGridView.CurrentRow.Cells[3].Value.ToString();
textBox5.Text = dataGridView.CurrentRow.Cells[4].Value == null ? "" : dataGridView.CurrentRow.Cells[4].Value.ToString();
textBox6.Text = dataGridView.CurrentRow.Cells[5].Value == null ? "" : dataGridView.CurrentRow.Cells[5].Value.ToString();
textBox7.Text = dataGridView.CurrentRow.Cells[6].Value == null ? "" : dataGridView.CurrentRow.Cells[6].Value.ToString();
textBox8.Text = dataGridView.CurrentRow.Cells[7].Value == null ? "" : dataGridView.CurrentRow.Cells[7].Value.ToString();
textBox10.Text = dataGridView.CurrentRow.Cells[9].Value == null ? "" : dataGridView.CurrentRow.Cells[9].Value.ToString();
}


2 - شما اطلاعات دیتابیس رو در داخل GridView ها وارد می کنید، خوب اگه این اطلاعات رو ذخیره کنید تا در اجرای بعدی برنامه از اونها استفاده کنید، اگه از instance دیگری از این برنامه یا بطور دستی اطلاعات داخل دینابیس تغییر کنه، شما همچنان با اطلاعات ذخیره شده قدیمی کار خواهید کرد.
پس کار صحیحی نیست که شما اطلاعات GridView ها رو برای استفاده بعدی ذخیره کنید. در ضمن ساخته شدن control ها در یک loop وقتی نمی گیره، اونی که رمان گیره پر کردن اونها از روی دیتابیس هستش.
اگر فکر می کنید که فرآیند import اطلاعات داخل GridView ها همچنان سنگین هستش در حالیکه میزان رکوردهای دیتابیس شما خیلی زیاد نیست بهتره کدهای برنامه تون رو بازنگری کنید
و اگر رکوردهای دیتابیس شما واقعا زیاد هست، می تونید در GridView ها از Pager و Filter استفاده کنید و در هر لحظه فقط بخش مورد نیازتون رو در GridView وارد کنید.

3-


// this = current form
this.WindowState = FormWindowState.Minimized;
this.WindowState = FormWindowState.Maximized;



// this = current form
foreach (Control c in this.Controls)
{
if (c is Button)
c.Visible = false;
}

va2012
سه شنبه 09 خرداد 1391, 21:33 عصر
خیلی ممنون دوستان . انجام دادم ولی هنوز همون ارور رو میده . بذارین من کاملتر توضیح بدم :

خوب من زمان اجرا میام یک سری کنترل از هر نوعی ( حالا مثلا گرید ویو Telerik ) درست میکنم و اون ها رو به فرم اضافه میکنم . در اینجا همه کنترل ها با نام متغیر dataGridView هست . خوب هر بار که دکمه کلیک بشه یک دیتاگرید جدید با نام جدید درست میشه مثلا dataGridView3و dataGridView2 وdataGridView1 و ... حالا من می خوام برای رویداد CellClick همه این دیتاگرید ها یک رویداد یکسان بنویسم ولی داخل اون متغیر های dataGridView ناشناخته هست. پس من میام و یک instance عمومی از این دیتاگرید میسازم که بتونم در رویداد CellClick به اون کنترل دسترسی داشته باشم و نظرم اینه که مشکل از این ساخت این instance عمومی هست که ارور میده. نمیدونم منظورم رو متوجه شدین یا نه ولی احتمال زیاد مشکل از همین جاست. چرا این رو میگم به خاطر اینکه برای همه گرید های ساخته شده یک رویداد CellFormatting نوشتم و مشکلی نبود. ولی اینجا که نام dataGridView وارد میشه مشکل ایجاد میکنه.

Telerik.WinControls.UI.RadGridView dataGridView = new Telerik.WinControls.UI.RadGridView();

اینم instance عمومی که تعریف کردم :

public partial class MainForm : Form
{
Telerik.WinControls.UI.RadGridView dataGridView = new Telerik.WinControls.UI.RadGridView();
{

va2012
سه شنبه 09 خرداد 1391, 21:41 عصر
این قسمت رو کامل متوجه نشدم یعنی چی : "شما اطلاعات دیتابیس رو در داخل GridView ها وارد می کنید، خوب اگه این اطلاعات رو ذخیره کنید تا در اجرای بعدی برنامه از اونها استفاده کنید، اگه از instance دیگری از این برنامه یا بطور دستی اطلاعات داخل دینابیس تغییر کنه، شما همچنان با اطلاعات ذخیره شده قدیمی کار خواهید کرد."

من جدول های دیتابیس رو دستی هم پر کردم و امتحان کردم همه چیز درست بود و اطلاعات هر جدول رو توی دیتاگرید مربوط به خودش نشون داد. اطلاعات اینقدر زیاد نیست که خیلی طول بکشه .منظور من این بود که وقتی چند تا کنترل در زمان اجرا با خصوصیات مشخص ساخته میشه باید هنگام لود فرم دوباره به همون تعداد کنترل ساخته بشه و خصوصیات هر کنترل به اون برگردونده بشه - آیا این کار که انجام دادم درست هست یعنی راه حل بهت و بهینه تری برای این کار وجود نداره؟

Mahyar.FF
سه شنبه 09 خرداد 1391, 21:57 عصر
من جدول های دیتابیس رو دستی هم پر کردم و امتحان کردم همه چیز درست بود و اطلاعات هر جدول رو توی دیتاگرید مربوط به خودش نشون داد. اطلاعات اینقدر زیاد نیست که خیلی طول بکشه .منظور من این بود که وقتی چند تا کنترل در زمان اجرا با خصوصیات مشخص ساخته میشه باید هنگام لود فرم دوباره به همون تعداد کنترل ساخته بشه و خصوصیات هر کنترل به اون برگردونده بشه - آیا این کار که انجام دادم درست هست یعنی راه حل بهت و بهینه تری برای این کار وجود نداره؟

بطور کل همیشه میشه ساختار و خصوصیات یک کنترل و حتی اطلاعات داخلش رو در قالب فایل xml ذخیره کرد و دوباره بازخونی کرد.
اما این یه ذره کار میبره. در ضمن باز هم میگم ساختن چند کنترل در Windows Forms در چند صدم ثانیه انجام میشه، یعنی اگه ساختار و خصوصیات کنترل ها رو هم ذخیره کنید، فکر نکنم بشه بهینه ترش کرد.
نمیدونم تونستم مفهوم رو برسونم.!

موفق باشید

va2012
سه شنبه 09 خرداد 1391, 22:14 عصر
مرسی من هم نگران همین زمان ساخت کنترل ها بودم که شما میفرمایید زمانی در حد چند صدم ثانیه هست. پس ظاهرا راه حل همین هست و روش بهینه تری نیست. هنوز توی سوال اولم گیر کردم !!!! بازهم همون ارور رو میده

Mahyar.FF
سه شنبه 09 خرداد 1391, 22:18 عصر
OK
محتوای Stack مربوط به Exception رو اینجا بزارید لطفا تا بفهمم مشکل از کجا می تونه باشه

va2012
سه شنبه 09 خرداد 1391, 22:28 عصر
شما پست آخر صفحه قبل رو خوندین من اونجا توضیح دادم ارور به خاطر چی هست : به خاطر این کد هست : فکر کنم برنامه نمیتونه تشخیص بده کدوم dataGridView مورد نظر هست.

Telerik.WinControls.UI.RadGridView dataGridView = new Telerik.WinControls.UI.RadGridView();

اینم ارور :

Object reference not set to an instance of an object

> Work Manager v2.exe!Works_Manager_v_1.MainForm.dataGridView_Cel lClick(object sender, Telerik.WinControls.UI.GridViewCellEventArgs e) Line 684 C#‎

Mahyar.FF
سه شنبه 09 خرداد 1391, 22:43 عصر
راست میگی، post آخر صفحه قبل رو ندیده بودم :لبخند:

شما می تونی از sender برای اشاره به gridview مورد نظر استفاده کنی:


private void dataGridView_CellClick(object sender, GridViewCellEventArgs e)
{
Telerik.WinControls.UI.RadGridView dgv = sender as Telerik.WinControls.UI.RadGridView;
if (dgv == null)
return;
textBox3.Text = dgv.CurrentRow.Cells[2].Value == null ? "" : dgv.CurrentRow.Cells[2].Value.ToString();
textBox4.Text = dgv.CurrentRow.Cells[3].Value == null ? "" : dgv.CurrentRow.Cells[3].Value.ToString();
textBox5.Text = dgv.CurrentRow.Cells[4].Value == null ? "" : dgv.CurrentRow.Cells[4].Value.ToString();
textBox6.Text = dgv.CurrentRow.Cells[5].Value == null ? "" : dgv.CurrentRow.Cells[5].Value.ToString();
textBox7.Text = dgv.CurrentRow.Cells[6].Value == null ? "" : dgv.CurrentRow.Cells[6].Value.ToString();
textBox8.Text = dgv.CurrentRow.Cells[7].Value == null ? "" : dgv.CurrentRow.Cells[7].Value.ToString();
textBox10.Text = dgv.CurrentRow.Cells[9].Value == null ? "" : dgv.CurrentRow.Cells[9].Value.ToString();
}

va2012
سه شنبه 09 خرداد 1391, 23:03 عصر
نه متاسفانه هنوز همون ارور رو میده . باید یکم روش کار کنم شاید درست شد.

راستی دو تا سوال دیگه : وقتی یک دیتاگرید ویو رو در زمان اجرا ساخته شد و اطلاعات یک جدول داخلش نشون داده شد چطور میشه عرض هر ستون رو تغییر داد؟

من از این کد معمول استفاده میکنم ولی پیغام میده که ستونی وجود نداره !!!!!!

dataGridView.Columns[0].Width = 150;

دوم اینکه چطور یک ستون ردیف برای هر گرید بسازم که با حذف هر سطر از اطلاعات شماره ردیف ها خودکار مرتب بشه چون قبلا برای ستون ردیف از id استفاده می کردم ولی بعد از حذف هر سطر شماره سطر رو از انتهای سطر حذف شده ادامه میده.

Mahyar.FF
سه شنبه 09 خرداد 1391, 23:37 عصر
اگر می خوای مشکل اول رو حل کنی، اینطوری عمل کن
اگه error در خط اول یعنی:

textBox3.Text = dataGridView.CurrentRow.Cells[2].Value == null ? "" : dataGridView.CurrentRow.Cells[2].Value.ToString();
هست، یا textBox3 وجود نداره، یا dataGridView وجود نداره یا CurrentRow نداریم یا CurrentRow.Cell[2] وجود نداره
که همه رو می تونی در پنجره Watch 1 تست کنی.
اگر هم error تو بقیه خطوط رخ میده، که مطمئنا ایراد از CurrentRow.Cell[n] هستش، یعنی اون cell خاص وجود نداره

در مورد سوال اول باید بگم لزوما نباید اطلاعات جدول داخل GridView وارد بشه بعد عرض هر ستون رو تغییر بدی
اینکار رو میشه در هنگام ساخته شدن هر ستون انجام داد
هر datagridview یه Event داره شبیه ColumnAdded که در اون می تونی از طریق پارامتر e.Column به ستون ساخته شده دسترسی داشته باشی


dataGridView.ColumnAdded += new GridViewColumnEventHandler(dataGridView_ColumnAdde d);

private void dataGridView_ColumnAdded(object sender, GridViewColumnEventArgs e)
{
e.Column.Width = 150;
}
اگه از RadGridView استفاده می کنی، ممکنه اسامی یه خورده فرق بکنه

در مورد سوال دوم، اگه در داخل Table مورد نظر، ستون id از نوع Identity باشه (خوبه Primary Key هم باشه)، در اینصورت ستون id همیشه یه شمارنده داره که وقتی سطر جدیدی شروع میشه بر اساس اون شمارنده بهش شماره میده.

va2012
چهارشنبه 10 خرداد 1391, 12:32 عصر
مرسی ولی TextBox ها همه وجود دارند و این خطا برای همه خط ها اتفاق میفته. همونطور که گفتم احتمالا dataGridView وجود نداره یعنی روی فرم ساخته شده ولی اسمش یه چیز دیگه هست مثلا radGridView1,radGridView2, ...

اما من همه رو به نام متغیر dataGridView ایجاد کردم . نمیدونم چه راهی هست. میشه یک رویداد رو مستقیما داخل یک حلقه نوشت ؟!!!!!!!!!!!!

اون رویداد ColumnAdded برای تلریک وجود نداره و من نتونستم معادلش رو پیدادکنم .

دیتابیس اکسس هست و فکر نکنم ستون id خاصیت Identity داشته باشه یا شاید من نتونستم پیدا کنم.

Mahyar.FF
چهارشنبه 10 خرداد 1391, 21:00 عصر
در مورد Column Size می تونی به شکل زیر عمل کنی:

radGridView.DataBindingComplete +=new Telerik.WinControls.UI.GridViewBindingCompleteEven tHandler(radGridView_DataBindingComplete);

private void radGridView1_DataBindingComplete(object sender, Telerik.WinControls.UI.GridViewBindingCompleteEven tArgs e)
{
Telerik.WinControls.UI.RadGridView dgv = sender as Telerik.WinControls.UI.RadGridView;
if (dgv.Columns.Count == 0)
return;
foreach (Telerik.WinControls.UI.GridViewColumn c in dgv.Columns)
{
c.Width = 150;
}
}

در مورد ستون Id در Access هم باید در بخش Design View بری، بعدش Data Type ستون Id رو Auto Number انتخاب کنی و در بخش Field Properties قسمت New Values رو برابر با Increment قرار بدی

87676

va2012
چهارشنبه 10 خرداد 1391, 23:45 عصر
ممنون از اینکه وقت میذارین و پیگیری می کنید . من هر دو مورد رو امتحان کردم. کد اول که اجرا نمیشه چون ظاهرا تعداد ستون ها رو صفر حساب می کنه و در مورد فیلد ID هم این کار رو همیشه انجام میدم ولی همونطور که قبلا گفتم با حذف یک سطر شماره ها از اول Sort نمیشن. مثلا 5 تا سطر داشتم و سطر 4 رو حذف کردم شماره ها شد : 1-2-3-5 و عدد آخر که 5 هست همونطور باقی موند.

Mahyar.FF
پنج شنبه 11 خرداد 1391, 11:51 صبح
در مورد اول لطفا PM تون رو نگاه کنید.
در مورد دوم، دیتابیس هایی که تا حالا دیدم، همچین کاری نمی کنند
اما شما می تونی یه ستون دیگه از نوع عددی در نظر بگیری و پس از درج یا خذف یک یا چند ستون در یک مرحله و با استفاده از یک تابع (که مقادیر رو بر اساس ستون Id و بصورت صعودی sort می کنه)، رکوردها رو از 1 الی آخر شماره گذاری کنی.
البته این کار رو در SQL میشه با استفاده از قابلیت Trigger طوری پیاده سازی کرد که خود SQL این کار رو هر دفعه بصورت اتواتیک انجام بده.
در ضمن لازمه یادآوری کنم که Id در Table ها مفهوم خاصی داره و اگه بعنوان Primary Key بخواد استفاده بشه، اونوقت میشه شناسه اون جدول و نباید در رکورد خاصی تغییر پیدا کنه!
خیلی وقتها که از GridView برای نشان دادن محتویات یک جدول استفاده می کنید، وجود ستونی که Primary Key هستش در Event ها خیلی حیاتی هست.