PDA

View Full Version : سوال: رخ دادن رویداد SelectedIndexChange در Form_Load



اوبالیت به بو
سه شنبه 07 آبان 1392, 21:30 عصر
درود بر شما

بنده یک متد دارم که قرار هست یک DropDownList یا کومبو باکس رو پر کنه. این متد در Form_Load فراخوانی می شود. پس از تریس کردن متوجه شدم زمانیکه دستورات مربوط به بایند کردن DropDownList در حال اجرا هستند، در قسمتی که DataSource به یک DataSet متصل میشه کنترل اجرای برنامه به رویداد SelectedIndexChange کومبو پرش می کنه و سعی در اجرای اون دستورات داره.

من چطور می تونم از این کار جلو گیری کنم؟ یعنی در Form_Load اجازه ندم که رویداد SelectedIndexChange کنترل کومبو من اجرا بشود؟

با سپاس از شما

veniz2008
سه شنبه 07 آبان 1392, 22:17 عصر
سلام.
نمیدونم چرا دنبال غیرفعال کردن این رویداد هستید ولی طبیعیت و ماهیت رویداد selectedindexchanged همینه که به هنگام بایند کردن اطلاعات به اون فعال میشه.
اگر با خطایی مواجه شدید و بخاطر این مورد هست خطا رو ذکر کنید ولی اگر قصد دارید (به هر دلیلی) از اجرای کدهاتون جلوگیری کنید بهتره از رویداد SelectionChangeCommited استفاده کنید.
در این حالت دیگه در فرم لود، کدهای این رویداد بر خلاف رویداد selectedindechanged اجرا نمیشه.
رویداد SelectionChangeCommited زمانی رخ میده که آیتم انتخاب شده تغییر کنه و این تغییر در کمبوباکس نمایش داده بشه.

اوبالیت به بو
چهارشنبه 08 آبان 1392, 09:59 صبح
خیلی ممنونم دوست من.

این رویداد در کنترل تلریک وجود ندارد؟

من در رویداد این کومبو نوشتم که اگر یک آیتم انتخاب شد، در یک کومبو دیگر فرزندان آن لیست شوند. مثل سناریو استان و شهرستان

veniz2008
چهارشنبه 08 آبان 1392, 10:20 صبح
آیا موقع لود شدن فرم با خطای مربوط به system.Data.DataRowView مواجه می شید؟
معمولا دوستان زمانی دنبال غیر فعال کردن این رویداد (برای بار اول یا همون فرم لود) میرن که چنین خطایی براشون رخ میده و در واقع قصد این رو دارند که با یکبار مهار کردن اجرای کدها که در زمان فرم لود رخ میده، به این مشکل غلبه کنند.
آیا برای شما حطایی رخ میده که قصد دارید از اجرا شدن کدهای selectedindexchanged در بار اول جلوگیری کنید؟
کلا دلیل اینکه نمیخواید در اجرای فرم لود، کدهای selectedindexchanged اجرا بشه چی هست؟

اوبالیت به بو
چهارشنبه 08 آبان 1392, 10:34 صبح
private void GetAllShips()
{
DataSet dsShips = new DataSet();

dsShips = DAL.Classes.Ships.SelectAllShips();

ddlShips.DataSource = dsShips;
ddlShips.DataMember = dsShips.Tables[0].TableName;
ddlShips.DisplayMember = "ShipName";
ddlShips.ValueMember = "ShipID";

ddlShips.Items.Insert(0, new Telerik.WinControls.UI.RadListDataItem("انتخاب نمایید"));
ddlShips.Items[0].Value = -1;
}

private void GetAllComplexes(int Ship_ID)
{
DataSet dsComplexes = new DataSet();

dsComplexes = DAL.Classes.Complexes.SelectByShipID(Ship_ID);

ddlComplexes.DataSource = dsComplexes;
ddlComplexes.DataMember = dsComplexes.Tables[0].TableName;
ddlComplexes.DisplayMember = "ComplexName";
ddlComplexes.ValueMember = "ComplexID";
}
private void ddlShips_SelectedIndexChanged(object sender, Telerik.WinControls.UI.Data.PositionChangedEventAr gs e)
{
GetAllComplexes(Convert.ToInt32(ddlShips.SelectedV alue.ToString()));
}
private void SparePartActions_Load(object sender, EventArgs e)
{
GetAllShips();
}



Ships: جدول پدر هست
Complexes فرزند Ships

خطای مورد نظر:

Input string was not in a correct format.

اوبالیت به بو
چهارشنبه 08 آبان 1392, 10:37 صبح
علت خطا این هست که قبل از ایمکه ایتم ها در Ships لیست شود اقدام به اجرای SelectedIndexChange میکند

اوبالیت به بو
چهارشنبه 08 آبان 1392, 10:56 صبح
دوست من اگر دقت کنی من از دستور Convert.ToInt32 استفاده کردم

veniz2008
چهارشنبه 08 آبان 1392, 11:52 صبح
بله حق با شماست.
دلیل خطا بخاطر این هست که همزمان هم از دیتاست برای پر کردن (بایند کردن) استفاده کردید و هم بصورت دستی اومدید آیتم "انتخاب کنید" رو اضافه کردید. اون value رو که برای آیتم "انتخاب کنید" در نظر گرفتید نامعتبر هست.
برای رفع مشکلتون به این شکل اقدام کنید :
ابتدا یک شی ComboboxItem رو بصورت سراسری تعریف کنید :

ComboboxItem item;
همچنین یک کلاس (داخل فرم) بصورت زیر تعریف کنید :

public class ComboboxItem
{
public string Text { get; set; }
public object Value { get; set; }

public override string ToString()
{
return Text;
}
}
درون فرم لود که کمبو رو پر می کنید به شکل زیر از این کلاس استفاده کنید (این کدها رو بعد از پر کردن دیتاتیبل بذارید، ولی دیگه دیتاتیبل رو به کمبو بایند نکنید):

item = new ComboboxItem();
item.Text = "انتخاب کنید";
item.Value = 0;
CmbOstan.Items.Add(item);
for (int i = 0; i < dt.Rows.Count; i++)
{
item = new ComboboxItem();
item.Text = dt.Rows[i]["OstanName"].ToString();
item.Value = dt.Rows[i]["OstanID"];
CmbOstan.Items.Add(item);
}
CmbOstan.SelectedIndex = 0;
برای بدست آوردن value هر آیتم هم بصورت زیر استفاده کنید :

(CmbOstan.SelectedItem as ComboboxItem).Value

اوبالیت به بو
چهارشنبه 08 آبان 1392, 22:41 عصر
خیلی سپاس گذار هستم دوست خوب من. ممنون که وقت گذاشتید و این کد رو اماده کردید.

اما مساله اینجاست که من در فرم خودم چندین کومبو دارم و این کار برای من بسیار هزینه بر است. این نکته اول.
نکته دوم اینکه من از کامپوننت RadDropDownList شرکت Telerik استفاده می کنم.

آیا راه کم هزینه تری وجود نداره؟

در کل سیستم های دیگه به چه صورت کار می کنند؟ من فکر می کنم باید راه حلی وجود داشته باشه. من چون وب کار می کنم خیلی راحت با این مساله کنار میام ولی در ویندوز (بعد از مدت ها) هنوز راه حلی براش پیدا نکردم.

veniz2008
پنج شنبه 09 آبان 1392, 00:34 صبح
آیا راه کم هزینه تری وجود نداره؟

در کل سیستم های دیگه به چه صورت کار می کنند؟ من فکر می کنم باید راه حلی وجود داشته باشه.
خوشبختانه وجود داره.
یه خورده باهاش ور رفتم و تونستم یه راهی پیدا کنم که خیلی هم ساده هست.
من اومدم به دیتاتیبل قبل از اینکه از جدول پرش کنم یک سطر اضافه کردم ( ()dt.Rows.Add ) و بعد دیتاتیبل رو از روی select ای که زدم پر کردم.
تا اینجا نتیجه کار این میشه که یک دیتاتیبلی دارم که سطر اول اون خالی هست (آماده شده برای پر شدن با کلمه "انتخاب کنید") و بقیه سطرهای اون هم از مقادیر جدول پر شده.
حالا قبل از اینکه این دیتاتیبل رو به کمبوباکس نسبت بدم، میام اون سطر اول رو پر میکنم. بعد از پر کردن سطر اول با کلمه "انتخاب کنید" میام و دیتاتیبل رو به کمبوباکس بایند میکنم.
فرض رو بر این گرفتم که نتیجه select من شامل دو ستون (OstanID و OstanName ) هست واسه همین در هنگام پر کردن سطر اول (با ایندکس 0) از ایندکس 0 و 1 برای ستون های دیتاتیبل استفاده کردم(شما میتونی نام ستون ها رو هم ذکر کنی).
کدها رو ملاحظه بفرمایید :

private void FrmQuestion_Load(object sender, EventArgs e)
{
SqlDataAdapter da = new SqlDataAdapter("Select * from TblOstan", con);
DataTable dt = new DataTable();
dt.Rows.Add();
da.Fill(dt);
dt.Rows[0][0] = 0;
dt.Rows[0][1] = "انتخاب کنید";
CmbOstan.DataSource = dt;
CmbOstan.DisplayMember = "OstanName";
CmbOstan.ValueMember = "OstanID";
}

اوبالیت به بو
یک شنبه 12 آبان 1392, 13:19 عصر
درود بر شما

معماری من اجازه استفاده از این کد رو نمی ده. من فقط باید بایند کنم. نمی دونم دوستان نمونه کد دیگه ای دارند؟

اوبالیت به بو
یک شنبه 12 آبان 1392, 13:56 عصر
سوال من اینه که چرا وقتی کومبو در حال پر شدن هست رویداد SelectedIndexChange اجرا میشه؟ در واقع چطور میشه این قسمت رو کنترل کرد. یعنی کاری کرد که وقتی داده واقعی درون کومبو وجود داشت اون موقع چیزی که مورد نظر ماست در رویداد SelectedIndexChange اجرا شود؟

veniz2008
یک شنبه 12 آبان 1392, 17:14 عصر
معماری من اجازه استفاده از این کد رو نمی ده. من فقط باید بایند کنم. نمی دونم دوستان نمونه کد دیگه ای دارند؟
من هم بایند کردم.
کاری که در پست 10 انجام دادم، بایند کردن منبع داده های کمبوباکس به یک دیتاتیبل هست.


سوال من اینه که چرا وقتی کومبو در حال پر شدن هست رویداد SelectedIndexChange اجرا میشه؟
در واقع چطور میشه این قسمت رو کنترل کرد. یعنی کاری کرد که وقتی داده واقعی درون کومبو وجود داشت اون موقع چیزی که مورد نظر ماست در رویداد SelectedIndexChange اجرا شود؟

همونطور که قبلا هم عرض کردم، رویداد SelectedIndexChange زمانی فعال میشه که شما بخوای کمبو رو به یک منبع داده ها (مثل دیتاتیبل) بایند کنید. چون در فرم لود شما کمبو رو بایند می کنید، این رویداد هم به ناچار اجرا میشه.
من واقعا هنوز درک نکردم که مشکل شما کجاست. الان که برنامه به درستی کار میکنه. وقتی خطایی رخ نمیده و در کوتاهترین کد ممکن هم به جواب می رسید دیگه مشکل کجاست؟
یا به جای SelectedIndexChange از رویداد SelectionChangeCommited استفاده کنید. این رویداد در واقع همون کار selectedindexchange رو انجام میده با این تفاوت که در لحظه بایند کردن، اجرا نمیشه و زمانیکه تمام ایتم ها داخل کمبو قرار بگیرن و شما اقدام به تغییر آیتم ها کنید فعال میشه.
یا اگر اصرار دارید که از selectedindexchange استفاده کنید (که من دلیل این اصرار رو درک نمیکنم) از یک متغیر bool (یا int یا ...) استفاده کنید و مقدار اولیه اونو false قرار بدید و بعد از بایند کردن دیتاتیبل به کمبو، مقدار اونو true کنید و در رویداد selectedindexchange ، با یک if چک کنید اگر مقدار متغیر true بود اونوقت کدهای مورد نظرتون اجرا بشن (هر چند به نظرم این روش مناسب نیست). اینطوری در لحظه فرم لود، زمانیکه کمبو بایند میشه دیگه رویداد selectedindexchange اجرا نمیشه ولی در دفعات بعدی چون مقدار متغیر true شده، کدها اجرا میشن.
اگر هم منظورتون از جمله آخری که نوشتید اینه که زمانیکه آیتم "انتخاب کنید" انتخاب میشه، رویداد selectedindexchange کار نکنه خوب با یک if ساده چک کنید که اگر selectedindex مخالف با 0 هست کدهاتون اجرا بشه (چراکه ایتم "اتخاب کنید" اولین آیتم هست و ایندکس اون 0 هست).

اوبالیت به بو
یک شنبه 12 آبان 1392, 22:41 عصر
درود بر شما جناب veniz2008

استفاده از SelectedIndexChange هیچ دلیل خاصی نیست. من نیم دونستم رویداد SelectionChangeCommited وجود داره. چون من همیشه وب کار می کنم و در اونجا از SelectedIndexChange استفاده می کنم بر حسب عادت فکر کردم در اینجا هم به همین صورت هست. SelectionChangeCommited رو تست می کنم و نتیجه رو بهتون اعلام می کنم. ممنونم از وقت و لطفی که کردید

veniz2008
یک شنبه 12 آبان 1392, 22:53 عصر
دوست من،
من این مورد رو تاکید کنم که منظور من از جملات بالا این نیست که رویداد SelectedIndexChange رویداد نامناسبی هست.
اتفاقا من خودم اکثر موارد از هیمن رویداد استفاده میکنم و هیچ مشکلی هم باهاش نداشتم ولی بعضی از مواقع هم با رویدادهای دیگه (بر حسب نیازم) کار میکنم.
بهرحال دست برنامه نویس باز هست که با توجه به نیازش، از بین رویدادهایی که در اختیارش هست رویداد مناسب رو انتخاب کنه.
شما تست کنید، خوشحال میشم بتونم کمکی بهتون بکنم.

اوبالیت به بو
دوشنبه 13 آبان 1392, 14:36 عصر
درود بر شما

در کومبو باکس پیش فرض دات نت این رویداد وجود دارد ولی در فهرست رویداد های کنترل DropDownList شرکت Telerik معادل این رویداد برابر هست با SelectedIndexChanging که البته درست کار کرد.

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

Mahmoud.Afrad
دوشنبه 13 آبان 1392, 18:23 عصر
برای برطرف شدن خطا ، رویداد رو به اینصورت بنویس:

private void ddlShips_SelectedIndexChanged(object sender, Telerik.WinControls.UI.Data.PositionChangedEventAr gs e)
{
DataRowView row = ddlShips.SelectedItem as DataRowView;
GetAllComplexes(Convert.ToInt32(row["id"]));
}


برای اینکه رویداد selectedchanged در هنگام لود فرم اتفاق نیفته کافیه رویداد رو بعد از پر شدن کمبوباکس به کمبو نسبت بدید. برای این کار به فایل designer فرم برید و خطی شبیه

this.ddlShips.SelectedIndexChanged += new System.EventHandler(this.ddlShips_SelectedIndexCha nged);

رو cut کنید در انتهای متد past کنید:

private void GetAllShips()
{
DataSet dsShips = new DataSet();

dsShips = DAL.Classes.Ships.SelectAllShips();

ddlShips.DataSource = dsShips;
ddlShips.DataMember = dsShips.Tables[0].TableName;
ddlShips.DisplayMember = "ShipName";
ddlShips.ValueMember = "ShipID";

ddlShips.Items.Insert(0, new Telerik.WinControls.UI.RadListDataItem("انتخا ب نمایید"));
ddlShips.Items[0].Value = -1;

this.ddlShips.SelectedIndexChanged += new System.EventHandler(this.ddlShips_SelectedIndexCha nged);
}

drstrike
دوشنبه 13 آبان 1392, 20:46 عصر
دوست من اگر دقت کنی من از دستور Convert.ToInt32 استفاده کردم

سلام
اگر خطا از تبدیل نوع داده هست می تونید رویداد selectedIndexChnaged رو به این شکل تغییر بدید:

private void ddlShips_SelectedIndexChanged(object sender, Telerik.WinControls.UI.Data.PositionChangedEventAr gs e)
{
int i;
if (int.TryParse(ddlShips.SelectedValue.ToString(), out i))
{
GetAllComplexes(i);
}
}

متد TryParse سعی میکنه پارامتر اول رو به int تبدیل کنه. اگه عملیات به درستی انجام شد مقدار true برمی گرده و پارامتر دوم مقداردهی میشه؛ درغیر این صورت متد مقدار false برمی گردونه و مقدار پارامتر دوم تغییر نمی کنه


اما مساله اینجاست که من در فرم خودم چندین کومبو دارم و این کار برای من بسیار هزینه بر است. این نکته اول.
نکته دوم اینکه من از کامپوننت RadDropDownList شرکت Telerik استفاده می کنم.

آیا راه کم هزینه تری وجود نداره؟

با استفاده امکان Find & Replace ویژوال استودیو تغییرات رو روی همه فرم ها اعمال کنید؛ بطوریکه متدتون رو کامل انتخاب کنید، کلیدهای Control + H رو بزنید. توی قسمت Replace هم متد تحت شرط رو وارد کنید. ضمنا اگه تیک Match Case و Match Whole Word رو بزارید و ناحیه جستجو رو هم روی Current Project تنظیم کنید زیر 5دقیقه هم تغییرات اعمال میشه!


سوال من اینه که چرا وقتی کومبو در حال پر شدن هست رویداد SelectedIndexChange اجرا میشه؟ در واقع چطور میشه این قسمت رو کنترل کرد. یعنی کاری کرد که وقتی داده واقعی درون کومبو وجود داشت اون موقع چیزی که مورد نظر ماست در رویداد SelectedIndexChange اجرا شود؟
همونطور که خودتونم هم گفتید باید کنترلش کرد که اینکار اغلب تحت یه شرط انجام میشه (بهش شرط نگهبان هم میگن).
و چون توی برنامه رویداد selectedIndexChanged رو توی design mode هندل کردید بخاطر همین بمحض تغییرات در Iemsهای DropDonwlist این رویداد اجرا میشه. راه حلش (توی پست قبل هم توضیح دادن) اینه که تو فایل designer.cs فرم مربوطه دستوری که این رویداد رو هندل میکنه برداری و بعد از اجرای متد GetAllComplexes بزارید که هزینه زمانیه بالایی داره

موفق باشید

علی متقی پور
دوشنبه 13 آبان 1392, 20:48 عصر
با سلام

راستش فرصت نکردم همه جواب ها رو بخونم پس اگر حرف تکراری ای زدم معذرت میخوام

دو راه دارید

1. حرفه ای: ایونت مربوطه رو در آخرین خط کدهای ایونت لود فرم بنویسید تا در حین فرم لود رخ ندهد

2. مبتدی: یک اینام برای فرمت تعریف کنی که مثلا مقدار اولیه اش UnLoad هست و در پایان رخداد فرم لود مقدارش میشه Load. و خب تو ایونت مربوطه کامبو باکس شرط بذاری حتما این اینام برابر Load باشه

اوبالیت به بو
پنج شنبه 16 آبان 1392, 18:42 عصر
درود بر شما

با سپاس از همه دوستانی که وقت گذاشتند و کمکم کردند. خیلی از شما ممنونم.

چگونه مشکل حل شد:

همان طور که جناب Mahmoud.Afrad فرمودند خط مربوط به رویداد SelectedIndexChanged که در Designer فرم نوشته شده رو حذف و در قسمتی که DropDownList بایند می شه گذاشتم. و مساله رفع شد.

اوبالیت به بو
جمعه 17 آبان 1392, 10:16 صبح
جناب Mahmoud.Afrad حالا به یک مشکل دیگه برخورد کردم.

من می خوام وقتی DropDownList بایند شد یک آیتم به اون Insert کنم. بوسیله این دستور:

ddlShips.Items.Insert(0, new Telerik.WinControls.UI.RadListDataItem("انتخا ب نمایید"));

اما پیغام خطایی دریافت می کنم مبنی بر اینکه وقتی DropDownList بایند شده من نمی توانم آیتم دیگه ای رو به اون Insert کنم.

چرا این کار رو می خوام انجام بدم؟

وقتی که آیتم های DropDownlist پدر نمایش داده می شوند، اگر اولین آیتم فرزندی در DropDownList دوم داشته باشد، فرزندان نمایش داده نمی شود. بلکه باید یکبار یک آیتم دیگر رو انتخاب کرد سپس دوباره آیتم مورد نظر رو انتخاب کرد. یعنی یکبار SelectedIndexChange به صورت دستی باید اتفاق بیافتد وگرنه نمیشه دید.

Mahmoud.Afrad
جمعه 17 آبان 1392, 15:44 عصر
میتونی یک آیتم "انتخاب کنید" به گزینه ها اضافه کنی. این کار رو از طریق کوئری sql میتونی انجام بدی. یا اینکه به دیتاتیبل اضافه کنی که کار بیشتری میبره:

private void GetAllShips()
{
DataSet dsShips = new DataSet();

dsShips = DAL.Classes.Ships.SelectAllShips();
dsShips.Tables[0].Rows.Add(-1, "انتخاب کنید");
dsShips.Tables[0].DefaultView.Sort = "ShipID asc";
ddlShips.DataSource = dsShips;
ddlShips.DataMember = dsShips.Tables[0].TableName;
ddlShips.DisplayMember = "ShipName";
ddlShips.ValueMember = "ShipID";

this.ddlShips.SelectedIndexChanged += new System.EventHandler(this.ddlShips_SelectedIndexCha nged);
}

در رویداد هم چک کن id منفی یک نباشه.

private void ddlShips_SelectedIndexChanged(object sender, Telerik.WinControls.UI.Data.PositionChangedEventAr gs e)
{
DataRowView row = ddlShips.SelectedItem as DataRowView;
int id = Convert.ToInt32(row["id"]);
if (id != -1)
{
GetAllComplexes(id);
}
}

اوبالیت به بو
یک شنبه 19 آبان 1392, 10:53 صبح
البته جناب Mahmoud.Afrad این روش یک اشکال کوچیک داره و اون اینه اگر در دیتابایس ما یک id با مقدار -1 داشته باشیم هیچ وقت نمی تونیم بهش دسترسی داشته باشیم

اوبالیت به بو
شنبه 25 آبان 1392, 00:52 صبح
درود بر شما

مشکلم حل شد.

رویداد ها رو به حالت اول برگردوندم و در متدهایی که رکوردهای مربوط به DropDownList ها بود، به جای استفاده از DataSource از حلقه for برای اضافه نمودن آیتم ها استفاده کردم.