PDA

View Full Version : سوال: انتقال Focus از کنترلی به کنترول بعدی توسط کلید Enter به صورت پویا



alireza_tavakol
شنبه 09 خرداد 1388, 05:26 صبح
من می خوام یک کد کلی بنویسم که توی هر فرمی قرار دادم اگه کلید Enter فشار داده شد بدونه اینکه بدونم Focus روی کدوم شی بوده به شی بعدی که Tab order یکی بزرگتر از شی جاری است انتقال پیدا کنه

لطفا راهنمایی کنید

Happy_davood
شنبه 09 خرداد 1388, 09:34 صبح
خوب من قبلاً این مشکل رو تجربه کردم و در نهایت بهترین راه حل رو هم پیدا کردم .
بهترین راه حل این هست که کنترل ، مثلاً TextBox موقع فشار داده شدن Enter به جای کلید Enter کلید Tab رو دریافت کنه . در این حالت عملکردش هم دقیقاً مثل Tab و کاملاً استاندارد میشه .

برای این کار یه کلاس از روی کلاس TextBox مشتق می کنید و با یه کم تغییرات ، تو پروژه به جای TextBox عادی از TextBox مشتق شده استفاده می کنید .

تغییرات داخل کلاس جدید هم این هست :




protected override bool ProcessDialogKey(System.Windows.Forms.Keys keyData)
{
System.Windows.Forms.Keys Key = keyData & System.Windows.Forms.Keys.KeyCode;

if (Key == System.Windows.Forms.Keys.Enter)
return this.ProcessDialogKey(System.Windows.Forms.Keys.Ta b);

return base.ProcessDialogKey(keyData);
}


به همین راحتی . اینجوری داخل فرم هاتون مجبور نیستید چیز اضافی بنویسید .

ASKaffash
شنبه 09 خرداد 1388, 09:52 صبح
سلام
یک راه استفاده از ورائت است یک فرم شخصی بنام MyForm :


public partial class MyForm : Form
{
public MyForm()
{
InitializeComponent();
}
private void MyForm_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Enter)
{
e.Handled = true;
SendKeys.Send("{TAB}");
}
}
}

حال همه فرمهای شما از این فرم ارث ببرند (KeyPreview فراموش نشود)

Happy_davood
شنبه 09 خرداد 1388, 14:00 عصر
البته راه حل دوستمون هم بد نیست ولی در این روش مجبور هستید در تمام فرم ها اون چند سطر کد رو بنویسید که این اصلاً خوب نیست .

ضمناً این موضوع منجر به یه بحث دیگه هم میشه .
به نظر من مخصوصاً در پروژه های بزرگ اصلاً نباید از کنترل ها به صورت عادی استفاده کرد . بلکه باید ازشون مشتق کرد و از مشتق شده ها استفاده کرد (البته میشه به مرور زمان و با ایجاد شدن مشکل هم کنرتل ها رو مشتق کرد و تو پروژه Replace کرد) ولی تجربه من این بوده که تقریباً تمام کنترل ها رو مجبور شدم مشتق کنم . بنابراین هروقت می خوام یه پروژه جدید شروع کنم از یه Library که شامل بیشتر کنترل ها به صورت مشتق شده هست استفاده می کنم .

مثلاً دیتاگریدی باید با زدن Enter به جلو حرکت بکنه و نه پایین .
یا در تمام فرم های پروژه های من میشه روی گرید کلیک راست کرد و "ارسال به اکسل" کرد .
TextBox باید فقط عدد بگیره نه حرف
TextBox ی که باید فقط فارسی قبول کنه نه انگلیسی و .....

ASKaffash
شنبه 09 خرداد 1388, 14:13 عصر
البته راه حل دوستمون هم بد نیست ولی در این روش مجبور هستید در تمام فرم ها اون چند سطر کد رو بنویسید که این اصلاً خوب نیست .

ضمناً این موضوع منجر به یه بحث دیگه هم میشه .
به نظر من مخصوصاً در پروژه های بزرگ اصلاً نباید از کنترل ها به صورت عادی استفاده کرد . بلکه باید ازشون مشتق کرد و از مشتق شده ها استفاده کرد (البته میشه به مرور زمان و با ایجاد شدن مشکل هم کنرتل ها رو مشتق کرد و تو پروژه Replace کرد) ولی تجربه من این بوده که تقریباً تمام کنترل ها رو مجبور شدم مشتق کنم . بنابراین هروقت می خوام یه پروژه جدید شروع کنم از یه Library که شامل بیشتر کنترل ها به صورت مشتق شده هست استفاده می کنم .

مثلاً دیتاگریدی باید با زدن Enter به جلو حرکت بکنه و نه پایین .
یا در تمام فرم های پروژه های من میشه روی گرید کلیک راست کرد و "ارسال به اکسل" کرد .
TextBox باید فقط عدد بگیره نه حرف
TextBox ی که باید فقط فارسی قبول کنه نه انگلیسی و .....
سلام
دوست من حتی نیاز نیست یک خط هم بنویسید

esmaeily-hosein
شنبه 09 خرداد 1388, 14:44 عصر
اینم نوعی دیگر .

Sendkeys.Send("\t");
اینو تو Keydown مربوط به تست باکس میزاری بعد همه کنترلهاتو به Event مربوط به این کنترل نسبت میدی

Happy_davood
شنبه 09 خرداد 1388, 15:20 عصر
سلام
دوست من حتی نیاز نیست یک خط هم بنویسید


درسته به ابتدای کلاس دقت نکرده بود .
منتهی تو این روش شما دیگه کلید Enter رو برای همیشه از دست دادید !

Happy_davood
شنبه 09 خرداد 1388, 15:26 عصر
روش دوستمون esmaeily-hosein هم خوبه و با این کار


همه کنترلهاتو به Event مربوط به این کنترل نسبت میدی

نیاز به کد نویسی زیادی نداریم . ولی باز هم مجبور هستیم در هر فرم یه سری کد تکراری بنویسیم که ممکنه گاهاً هم فراموش بشه . ضمناً باید برگشت و در تمام فرم هایی که قبلاً نوشته شده این کار رو انجام داد.

ولی بار روشی که من گفتم دیگه نیاز به هیچ تغییری در کد نیست . تقریباً میشه گفت اینجوری از مفاهیم شی گرایی هم بهتر و به صلاحتر استفاده کردیم .

esmaeily-hosein
شنبه 09 خرداد 1388, 16:33 عصر
ولی در اکثر مواقع ما نمیخواهیم تمام Enter های خودمون تبدیل به Tab بشن حساب کن در جاهایی مثل توضیحات اگر به جای Enter کلید tab پاس داده بشه دارو زندگی طرف به هم میریزه! منطقی ترین راهی که الان به نظرم میرسه استفاده از Extended Control است .

نمونشو میزارم استفاده کنید با اضافه کردن این کنترل به فرمتون خاصیتی به نام EnterMoving به textbox هاتون اضافه میشه که با true کردن اون میتونید بین کنترل ها حرکت کنید .

Happy_davood
شنبه 09 خرداد 1388, 17:07 عصر
دقیقاً همینطور . ما نمی خواهیم که همیشه Enter به جای Tab کار کنه .

خوب من اون قسمت رو واگذار کردم به خودتون .

دقیقش این هست که در روشی که من گفتم یه پراپرتی خیلی جالب و به درد بخور روی کلاس جدید TextBox اضافه کنید که با True یا False کردن اون پراپرتی امکان انتقال به کنترل بعدی فعال یا غیر فعلا بشه . من هم اتفاقاً دقیقاً همین کار رو انجام دادم :


private Boolean moveToNextOnEnterKey;
.
.
.
public Boolean MoveToNextOnEnterKey
{
set
{
this.moveToNextOnEnterKey = value;
}
get
{
return this.moveToNextOnEnterKey;
}
}

protected override bool ProcessDialogKey(System.Windows.Forms.Keys keyData)
{
System.Windows.Forms.Keys Key = keyData & System.Windows.Forms.Keys.KeyCode;

if (Key == System.Windows.Forms.Keys.Enter && this.moveToNextOnEnterKey == true)
return this.ProcessDialogKey(System.Windows.Forms.Keys.Ta b);

return base.ProcessDialogKey(keyData);
}

esmaeily-hosein
شنبه 09 خرداد 1388, 17:32 عصر
دقیقاً همینطور . ما نمی خواهیم که همیشه Enter به جای Tab کار کنه کد شما که درسته من کد ASKaffash (http://barnamenevis.org/forum/member.php?u=63973) گفتم .
ولی در کل TextBox مشتق شده و EnterProvider جفتشون روش های منطقی و درستی هستند .

prankster
شنبه 09 خرداد 1388, 21:08 عصر
یک روش دیگر هم اضافه کردن extention به کلاس Control است.
کلاس زیر را در پروژه اضافه کنید:


public static class ControlExtensions
{
public static void ChangeEnterKey(this Control c, bool change)
{
c.KeyDown -= KeyDownHandler;

if (change)
c.KeyDown += KeyDownHandler;
}

private static void KeyDownHandler(object sender, KeyEventArgs e)
{
if (e.KeyData == Keys.Enter)
{
e.Handled = true;
e.SuppressKeyPress = true;
SendKeys.Send("{TAB}");
}
}
}


از آنجا که تمامی کنترل ها از کلاس Control ارث می برند، همه متدی با نام ChangeEnterKey را خواهند داشت. به راحتی می توانید با true یا false ارسال کردن به این متد کلید enter را روی کنترل مورد نظر به tab تغییر دهید:

مثلا در فرم 1 با کنترل textBox1:


textBox1.ChangeEnterKey(true);


می توانید متد مورد نظر را روی فرم صدا بزنید، در این صورت کلید enter بر روی فرم عملکرد tab را خواهد داشت و بر روی همه کنترل های فرم عمل می کند:


public Form1()
{
InitializeComponent();
this.KeyPreview = true;
this.ChangeEnterKey(true);
}

ASKaffash
یک شنبه 10 خرداد 1388, 11:03 صبح
سلام
اگر به کلید Enter در یک فرم خاص نیاز نباشد برای آن فرم خاص خاصیت KeyPreview را false میکنیم