شرط مربوط به نمایش برچسب مرتبط با جعبه ی متن!

kern

Member
سلام.
فرم زیر رو مد نظر بگیرید:

attachment.php


در حالت عادی برچسب های "غیر مجاز" فعال نیستن!
میخوام بعد از کلیک بر روی کلید ثبت، هر کدام از جعبه ها که خالی بودن برچسب جلوی اونها فعال بشه!
کدش چی میشه؟! من کد زیر رو نوشتم ولی جواب نگرفتم! اصلا وارد حلقه ی foreach نمیشه!
بعد از این که وارد حلقه شد، برچسب مربوط به هر جعبه ی متن رو چه جوری تشخیص بدم؟!
attachment.php
 

پیوست ها

  • Ifff.png
    Ifff.png
    3 کیلوبایت · بازدیدها: 7
  • if code.png
    if code.png
    13.9 کیلوبایت · بازدیدها: 8
آخرین ویرایش:

the_king

مدیرکل انجمن
روبروی هر TextBox یک Label دارید :

برای هر TextBox از حلقه foreach و بررسی کنترل های داخل Controls استفاده می کنیم تا بررسی کنیم کدومشون TextBox اند.

برای پیدا کردن Label ای که مقابل یک TextBox قرار داره باید مختصات مکانی شون رو بررسی کنیم، اونی که سمت چپ اش و کمترین فاصله رو ازش داره رو پیدا می کنیم.

کد:
[COLOR="#A9A9A9"]    public partial class Form1 : Form
    {
[/COLOR]
        private List<Control> _labels = new List<Control>();

[COLOR="#A9A9A9"]        public Form1()
        {
            InitializeComponent();
        }
[/COLOR]
        private void button1_Click(object sender, EventArgs e)
        {
            var clist = new List<Control>();
            bool allCtl = true;
            foreach (var ctl in _labels)
            {
                ctl.Visible = false;
            }
            foreach (Control ctl in Controls)
            {
                if (ctl is TextBox)
                {
                    if (string.IsNullOrEmpty(ctl.Text.Trim()))
                    {
                        clist.Add((Control)ctl);
                    }
                    else
                    {
                        allCtl = false;
                    }
                }
            }
            if (allCtl)
            {
                MessageBox.Show(this, "Please Fill All Text Box", "Result", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            else if (clist.Count > 0)
            {
                foreach (var ctl in clist)
                {
                    int min = int.MaxValue;
                    Control cmin = null;
                    foreach (Control other in Controls)
                    {
                        if ((other is Label) && (other.Right < ctl.Left))
                        {
                            int dist = Distance(other.Right, other.Top, ctl.Left, ctl.Top);
                            if (dist < min)
                            {
                                min = dist;
                                cmin = other;
                            }
                        }
                    }
                    cmin.Visible = true;
                    _labels.Add(cmin);
                }
                clist[0].Select();
            }
            else
            {
                MessageBox.Show("Done!", "Result", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        private int Distance(int x1, int y1, int x2, int y2)
        {
            return (int)Math.Sqrt(Math.Pow(x1 - x2, 2) + Math.Pow(y1 - y2, 2));
        }
[COLOR="#A9A9A9"]    }[/COLOR]
 

kern

Member
اگه بخوام از errorProvider استفاده کنم چی؟!
نمیخوام برای هر کنترل جداگانه بنویسم!
اینجوری نوشتم بازم حلقه اجرا نمیشه!

کد:
foreach (Control control in this.Controls)
                {
                    if (control is TextBox)
                        if (control.Text == "")
                            errorProvider1.SetError(control, "Can't Empty");
                    control.Focus();
                    return;
                }
 

the_king

مدیرکل انجمن
اگه بخوام از errorProvider استفاده کنم چی؟!
نمیخوام برای هر کنترل جداگانه بنویسم!
اینجوری نوشتم بازم حلقه اجرا نمیشه!

کد:
foreach (Control control in this.Controls)
                {
                    if (control is TextBox)
                        if (control.Text == "")
                            errorProvider1.SetError(control, "Can't Empty");
                    control.Focus();
                    return;
                }

کدی که براتون نوشته بودم همه TextBox ها رو یکجا بررسی می کنه.
از ErrorProvider هم می توانید استفاده کنید فقط عیب اش اینه که متن خطا را با Tooltip نشون میده.

حلقه ای که نوشته اید یه ایراد کوچیک داره، if ای که نوشنه اید بدون { و } داره اجرا میشه و فقط یک سطر دستور بعدی رو شامل خواهد شد،
اون ()control.Focus و return نه جزئی از if اول هستند و نه جزئی از if دوم. چه کنترل اول TextBox باشه و چه نباشه و چه خالی باشه و چه نباشه
به هر حال با بررسی اولین کنترل از حلقه خارج می شوید و دیگه کنترل های بعدی بررسی نمیشه. برای همینه که مجالی برای ادامه یافتن حلقه for نیست
و کاری که مطلوبه انجام نمیده.

کد:
foreach (Control control in this.Controls)
{
    if (control is TextBox)
        if (control.Text == "")
[COLOR="#0000FF"][B]        {[/B][/COLOR]
            errorProvider1.SetError(control, "Can't Empty");
            control.Focus();
            return;
[B][COLOR="#0000FF"]        }[/COLOR][/B]
}
 

kern

Member
کدی که براتون نوشته بودم همه TextBox ها رو یکجا بررسی می کنه.
از ErrorProvider هم می توانید استفاده کنید فقط عیب اش اینه که متن خطا را با Tooltip نشون میده.
از اون کد سر در نیاوردم! در ضمن متن خطا رو تو یه برچسب نشون دادم! (بالای صفحه ی فرم)

برای اینکه Icon مربوط به errorProvider بعد از اینکه متن کنترل مربوطه عوض شد، پاک بشه از دستور زیر استفاده میکنم:

errorProvider1.Clear();

درسته؟! یا روش بهتری هم هست؟!
 

the_king

مدیرکل انجمن
از اون کد سر در نیاوردم! در ضمن متن خطا رو تو یه برچسب نشون دادم! (بالای صفحه ی فرم)

برای اینکه Icon مربوط به errorProvider بعد از اینکه متن کنترل مربوطه عوض شد، پاک بشه از دستور زیر استفاده میکنم:

errorProvider1.Clear();

درسته؟! یا روش بهتری هم هست؟!

اگه هدف فقط ناپدید شدن اون آیکون باشه هم کافیه و هم مناسب، فقط ممکنه بخواهید به روتین تون مواردی مثل زرد/نارنجی شدن رنگ زمینه TextBox یا انیمیشن کادر TextBox رو اضافه کنید.

Preview.gif


مشاهده پیوست NotifyTextBox.zip
 

kern

Member
اگه هدف فقط ناپدید شدن اون آیکون باشه هم کافیه و هم مناسب، فقط ممکنه بخواهید به روتین تون مواردی مثل زرد/نارنجی شدن رنگ زمینه TextBox یا انیمیشن کادر TextBox رو اضافه کنید.

Preview.gif


مشاهده پیوست 109906
بسیار عالی !
ولی تو پروژه ی خودم نتونستم اضافه ش کنم!
 

the_king

مدیرکل انجمن
بسیار عالی !
ولی تو پروژه ی خودم نتونستم اضافه ش کنم!

فایل ClassNotify.cs رو از داخل پروژه بردارید و در پوشه پروژه خودتون کنار سایر فایل ها کپی کنید.
در ویژوال استدیو که پروژه تون رو باز کرده اید در منوی Project گزینه Add Existing Item را انتخاب کرده و فایل ClassNotify.cs رو در جایی که کپی کرده اید انتخاب کنید.
توی فرم های پروژه تون که می خواهید ازش استفاده کنید ابتدای کد یکسری using هست، به اونها سطر ;using NotifyTextBox رو اضافه کنید.
بعد هر جا که خواستید روی کنترل ای مثل textBox1 اجرا بشه بنویسید :
کد:
Notify n = new Notify();
n.Show(textBox1);
 

kern

Member
دیگه تاپیک جدید نزنم همینجا سوالم رو بپرسم!
کدهایی که خیلی تکرار میشن رو تو یه کلاس بنویسم؛ بعد از همین شیوه استفاده کنم اصولی هست!؟
مثلا کد زیر رو تو فرم‌ها خیلی تکرار می‌کنم:
کد:
void ClearControlText(Control c)
        {
            if (c is TextBox)
            {
                c.Text = "";
            }


            else if (c is ComboBox)
            {
                c.Text = "";
            }


            else if (c.HasChildren)
            {
                foreach (Control child in c.Controls)
                {
                    ClearControlText(child);
                }
            }            
        }



اینو چه جوری کلاسش کنم؟!
 
آخرین ویرایش:

the_king

مدیرکل انجمن
دیگه تاپیک جدید نزنم همینجا سوالم رو بپرسم!
کدهایی که خیلی تکرار میشن رو تو یه کلاس بنویسم؛ بعد از همین شیوه استفاده کنم اصولی هست!؟
مثلا کد زیر رو تو فرم‌ها خیلی تکرار می‌کنم:
کد:
void ClearControlText(Control c)
        {
            if (c is TextBox)
            {
                c.Text = "";
            }


            else if (c is ComboBox)
            {
                c.Text = "";
            }


            else if (c.HasChildren)
            {
                foreach (Control child in c.Controls)
                {
                    ClearControlText(child);
                }
            }            
        }



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

معمولا بر اساس موضوع کاری که انجام می دهند گروه بندی شون می کنید، فرضا الان یک کلاس عمومی برای موارد متفرقه مثلا به اسم Misc یا General (منوی Project، گزینه Add Class) لازم دارید.
این متد ClearControlText فقط احتیاج به یک مقدار ورودی c داره که در پارامتر دریافت اش می کنه، پس کاری با مقادیر متغیر های دیگه کلاس نداره، همچین متد هایی رو عموما static تعریف می کنند تا هم فراخوانی اش
راحت باشه و هم وابسته به نمونه شیء از کلاس نباشه :
کد:
using System.Windows.Forms;

namespace [B][COLOR="#0000FF"]YourProject[/COLOR][/B]
{
    public class General
    {
        [B][COLOR="#0000FF"]public static[/COLOR][/B] void ClearControlText(Control c)
        {
            if (c is TextBox)
            {
                c.Text = "";
            }
            else if (c is ComboBox)
            {
                c.Text = "";
            }
            else if (c.HasChildren)
            {
                foreach (Control child in c.Controls)
                {
                    ClearControlText(child);
                }
            }
        }
    }
}

حالا اگر اسم namespace رو در کلاس مشابه آنچه در کد فرم های پروژه تان هست نوشته باشید در فرم هایتان (General.ClearControlText(this قابل اجرا است :
کد:
[COLOR="#A9A9A9"]        private void button1_Click(object sender, EventArgs e)
        {
[/COLOR]            General.ClearControlText(this);
[COLOR="#A9A9A9"]        }[/COLOR]

از آنجایی که متد رو static تعریف کرده ایم نیازی به نمونه شیء از کلاس General نبود و فقط به اسم کلاس احتیاج داره، حقیقتا اگر از کلاس یک نمونه شیء بسازید می بینید که شیء اصلا متدی به نام ClearControlText نداره :

general.png
 

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

بالا