آموزش اضافه کردن واترمارک به Textbox و Combobox در سی شارپ

چگونه به Textbox خودمان در سی شارپ Watermark اضافه کنیم؟ Textbox و combobox از جمله کنترل هایی است که بهنگام طراحی فرم های ویندوزی یا صفحات وب زیاد مورد استفاده قرار می گیرند. افزودن قابلیت watermark به این دو کنترل، فرم های ویندوزی ما را زیباتر و کاراتر می سازد. به عنوان مثال طراحی یک login form به صورت شکل 1 ممکن است بهتر از طراحی آن به صورت شکل 2 است. اما مشکل این جاست که textboxو combobox ای که در visual studio toolbox وجود دارند، قابلیت watermark شدن را در حالت عادی ندارند. پس در صورت نیاز باید به دنبال راهی برای افزودن این خاصیت به آن ها باشیم.

دوره های شبکه، برنامه نویسی، مجازی سازی، امنیت، نفوذ و ... با برترین های ایران
سرفصل های این مطلب
  1. بررسی موضوع
  2. راه حل
وب سایت توسینسو

بررسی موضوع

از جمله راه حل های نه چندان جالب برای watermark کردن تکست باکس، ایجاد یک کلاس و ارث بری آن کلاس از کلاس System.Windows.Forms.TextBox است.اصلی ترین قسمت این کلاس رویدادهای GotFocus و LostFocus می باشد. با روی دادن رخداد LostFocus – در صورت خالی بودن textbox – می توانیم متنی را که به عنوان watermark در نظر گرفته ایم، به ویژگی TextBox.text نسبت دهیم و هم زمان نیز رنگ متن را به رنگ دیگری مانند خاکستری تغییر دهیم. بدین ترتیب یک watermark textbox شبیه سازی می شود.!! با روی دادن رخداد GotFocus نیز می توانیم در صورت فعال بودن watermark ، متن درون textbox را پاک کرده و رنگ متن را سیاه تغییر دهیم. این کلاس می تواند دارای ساختاری مشابه زیر باشد.

public class WatermarkTextBox : TextBox
    {
        
        private bool _watermarkActive = true;

        public bool WatermarkActive
        {
            get { return _watermarkActive; }
            set { _watermarkActive = value; }
        }

        public WatermarkTextBox()
        {
            this._watermarkActive = true;
            this.Text = _watermarkText;
            this.ForeColor = Color.Gray;

            GotFocus += (source, e) =>
            {
                if (this._watermarkActive)
            {
                this._watermarkActive = false;
                this.Text = "";
                this.ForeColor = Color.Black;
            }
            };

            LostFocus += (source, e) =>
            {
                if (!this._watermarkActive && string.IsNullOrEmpty(this.Text)
                || ForeColor == Color.Gray)
            {
                this._watermarkActive = true;
                this.Text = _watermarkText;
                this.ForeColor = Color.Gray;
            }
            };

        }
    }

توجه: همانطور که ممکن است حدس زده باشید، راه بالا بیشتر شبیه به دور زدن مسئله است تا حل آن. برای این کار بهتر است به دنبال روش های بهتر و ساده تری باشیم. یکی از راه حل های دیگر استفاده از componentهایی است که شرکت های دیگر مانند telerik تولید میکنند. اما این راه حل هم زیاد قابل اطمینان نیست ( به عنوان مثال در بعضی موارد با زبان فارسی سازگاری خوبی ندارند) و بهتر است تا حد امکان از آن استفاده نشود.

راه حل

حال به ارائه یک راهکار برای این مسئله می پردازیم.همانطور که می دانید، در محیط ویندوز textboxهایی وجود دارند که در حالت عادی متنی به صورت watermark درون آن ها قرار گرفته است. پس می توان نتیجه گرفت که ویندوز خود قالبلیت watermark کردن را دارد. حال سوال اینجاست که ویندوز چگونه این کار را انجام می دهد. جواب این سوال در user32.dll نهفته است. ما در ابتدا باید بتوانیم به توابعی که این dll ارائه می دهد، دسترسی پیدا کنیم.(exported functions). سپس از طریق تابع مناسب و فراهم آوردن پارامترهای مناسب برای آن تابع، به watermark کردن textbox یا combobox خود بپردازیم.

  • نکته: به طور کلی، بسیاری از برنامه هایی که ضاهر ویندوزی دارند، در پس زمینه از user32.dll استفاده می کنند. User32.dll به gdi32.dll لینک شده است و بسیاری از عناصر واسط کاربر را render میکند.(با فراخوانی توابع GDI ای که gdi32.dll فراهم می کند)
  • تذکر: برای ادامه نیاز به آشنایی با مفهومی به نام Platform Invoke داریم که به دلیل دور شدن از اصل موضوع از توضیح آن خودداری کرده و تنها با ذکر مثال به کاربرد آن برای watermark کردن textbox و combobox اشاره می کنیم. در صورت نیاز به توضیح بیشتر می توانید عبارت های Platform Invoke یا dllImport را در MSDN جستجو کنید.

روش کلی کار به صورت زیر است:

  • ابتدا با استفاده از کلمات کلیدی static و extern یک تابع با نام SendMessage در بدنه کلاس نعریف می کنیم. SendMessage همچنین نام یکی از exported functionهای user32.dll نیز می باشد.
  • فضای نام System.Runtime.InteropServices را به لیست فضای نام ها اضافه می کنیم
  • سپس صفت dllImport را به متد ضمیمه می کنیم. dllImport به شما این امکان را می دهد که نام dll ای را که تابع مورد نظر (در اینجا SendMessage ) در آن قرار دارد تعیین کنید.

نکته: در هنگام استفاده از این روش بهتر است تابع تعریف شده در بدنه کلاس نامی مشابه با exported function موجود در dll داشته باشد.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace CueTxtCbo
{
    public partial class Form1 : Form
    {

        [DllImport("user32.dll")]
        private static extern IntPtr SendMessage(HandleRef hWnd, uint Msg, int wParam, [MarshalAs(UnmanagedType.LPWStr)] String lParam);

        public Form1()
        {
            InitializeComponent();
        }
    }
}

حال درون سازنده کلاس (یا هر جای مناسب دیگری) تابع SendMessage را برای watermark کردن تکست باکسی که روی فرم قرار داده ایم، فراخوانی می کنیم. هنگام فراخوانی تابع به جای پارامتر lParam متنی را که به عنوان watermark در نظر گرفته اید قرار دهید. اگر به جای پارامتر wParam مقدار 0 قرار دهید، تکست باکس به محض دریافت نشانگر ماوس، watermark خود را ازبین می برد. اما اگر به جای پارامتر wParam مقدار 1 بگزارید، تکست باکس waremark خود را به هنگام دریافت نشانگر ماوس از بین نبرده و watermark تنها در صورت وارد کردن متن توسط کاربر از بین می رود (امتحان کنید). به جای پارامتر Msg ، کد 0x1501 را قرار دهید. (در واقع همین کد است که باعث می شود تکست باکس شما حالت watermark به خود بگیرد) برای watermark کردن combobox، به جای پارامتر Msg کد 0x1703 را قرار دهید. همچنین به جای پارامتر wParam به دلخواه یکی از مقادیر 0 یا را قرار دهید. (در این مورد 0 یا 1 تاثیری در نتیجه ندارد)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace CueTxtCbo
{
    public partial class Form1 : Form
    {

        [DllImport("user32.dll")]
        private static extern IntPtr SendMessage(HandleRef hWnd, uint Msg, int wParam, [MarshalAs(UnmanagedType.LPWStr)] String lParam);

        public Form1()
        {
            InitializeComponent();

            SendMessage(new HandleRef(textBox1, textBox1.Handle), 0x1501, 1, "Type something here");

            SendMessage(new HandleRef(comboBox1, comboBox1.Handle), 0x1703, 0, "Select an Item ...");
            SendMessage(new HandleRef(comboBox2, comboBox2.Handle), 0x1703, 1, "Select an Item ...");
        }
    }
}

با دنبال کردن مراحل بالا، textbox و comboboxهایی مانند شکل زیر خواهید داشت:

وب سایت توسینسو

نویسنده: رامین تقی زاده

منبع: انجمن تخصصی فناوری اطلاعات ایران

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


نظرات