گفتگو هایی در باب سی شارپ

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلامی مجدد استاد
انگار حدودا ، بهتر پیدا کردم که مشکل از کجاست (اما هنوز دقیق متوجه نشدم) .
مشکل انگار از کدهای تغییر سایز در TransparentControl هست . ربطی به TransparentControlText نداره.
مثلا کدهای زیر ، مشکلی ندارن (این کد ، رویداد Button3_MouseUp در کد بالاست که تغییر کرده) (برای آپدیت و رسم ، بعد از کلیک روی دکمه ، موس را روی کنترل TransparentControl ببرید) :


کد:
        private void Button3_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
                this.transparentControl.TransparentControlText.Text = "salam";
            else if (e.Button == MouseButtons.Right)
                this.transparentControl.TransparentControlText.Text = "khobi?";
        }

یا

کد:
        private void Button3_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
                this.transparentControl.TransparentControlText.TextFont = this.Font;
            else if (e.Button == MouseButtons.Right)
                this.transparentControl.TransparentControlText.Text = "khobi?";
        }

اما این کد مشکل داره :


کد:
        private void Button3_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
                this.transparentControl.Size = new Size(250, 100);
            else if (e.Button == MouseButtons.Right)
                this.transparentControl.Size = new Size(180, 70);
        }

حالا داخل کلاس TransparentControlText مشکل خودش را نشون میده چون داخل رویداد TransparentControl_TextAutoSizeChanged ، کدِ this.TransparentControl.Size = fontSize.ToSize() را بکار بردم.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلامی مجدد
مشکل یافت شد. بخاطر این بود که داخل رویداد AllParents_Invalidated ، وقتی جابجایی یا تغییر اندازه صورت میگرفت ، متد InvalidateBackgroundsAndThisControl ، دو بار اجرا میشد. چون هر بار که این تابع اجرا میشه ، به کنترل والدش کاری نداره و کنترل والدش را invalidate نمیکنه.
بنابراین ، کد این رویداد را به زیر تغییر دادم و درست شد :


کد:
        private void AllParents_Invalidated(object sender, InvalidateEventArgs e)
        {
            // در این قسمت ، عمل Invalidate کردن یا همون رسم کردن کنترل TransparentControl را فقط روی اون کنترلی انجام میده که عملیات موس روی اون کنترل انجام گرفته باشه .
            // همچنین اگه مکان کنترل جاری مون تغییر کنه ، همون کنترل رسم میشه.
            if (this.Equals(TransparentControl.TranspControlEventDoingFlag) == true || this.IsLocationChangeDoingFlag == true)
                this.InvalidateBackgroundsAndThisControl();
        }

خیلی ممنون استاد علی که تا اینجا کمکم کردین. :rose:
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلامی مجدد استاد علی
میگم در آخرین تغییرات ، واسه ی هر 3 کلاسِ TransparentControl و TransparentControlBitmap و TransparentControlText ، متد سازنده ی بدون آرگومان ساختم . بعد ، از توی toolbox که این کنترل TransparentControl را به فرم ام اضافه میکنم ، اضافه میشه . برای تغییرات هم مشکلی نداره . اما مشکلش اینه که زمانی که کنترلِ TransparentControl را از توی فرم ام میخوام حذف کنم ، حذف میشه (برای حذف شدن هم مشکلی نداره) اما بعد از حذف ، ارورِ زیر را میده :


1.JPG

این را که ok میکنم ، دوباره یه ارور دیگه منتها این بار فقط شامل پیام خط آخرِ ارورِ بالا هست را میده.

دلیل اش چیه؟
برای رفع این مشکل باید چیکار کرد؟
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
بعد اینکه بعضی وقت ها که این کنترل TransparentControl را توی فرم اضافه میکنم ، دیزاینر فرم ، قاتی میکنه و همون ارور معروف رو میده (که دیگه صفحه ی دیزاینر در دسترس قرار نمیگیره . اما موقع اجرا ، مشکلی نداره) اما وقتی ویژال استودیو را ببندم و دوباره وارد پروژه ام بشم ، انگار مشکل حل میشه. چرا؟
کلا زیاد با صفحه ی دیزاینر ویژال استودیو سازگار نیست (البته مشکل نمایش کنترل رو نداره . فقط این مشکلاتی که گفتم را داره) . چرا؟ میشه کاریش کرد که این مشکلات را نداشته باشه؟
 

the_king

مدیرکل انجمن
سلامی مجدد استاد علی
میگم در آخرین تغییرات ، واسه ی هر 3 کلاسِ TransparentControl و TransparentControlBitmap و TransparentControlText ، متد سازنده ی بدون آرگومان ساختم . بعد ، از توی toolbox که این کنترل TransparentControl را به فرم ام اضافه میکنم ، اضافه میشه . برای تغییرات هم مشکلی نداره . اما مشکلش اینه که زمانی که کنترلِ TransparentControl را از توی فرم ام میخوام حذف کنم ، حذف میشه (برای حذف شدن هم مشکلی نداره) اما بعد از حذف ، ارورِ زیر را میده :


مشاهده پیوست 112671

این را که ok میکنم ، دوباره یه ارور دیگه منتها این بار فقط شامل پیام خط آخرِ ارورِ بالا هست را میده.

دلیل اش چیه؟
برای رفع این مشکل باید چیکار کرد؟
ارجاع هایی که به اشیاء میدهید رو بررسی کنید. اگر قرار است به مشخصه های شیء ای رجوع کنید هم باید مطمئن شوید که در آن لحظه null نیست و هم اگر مشخصه مربوط به ظاهر کنترل ئه، کنترل Handle داره و نابود نشده.
شما باید در هر زمان آمادگی این رو داشته باشید که با نابود شدن شیء کنترل تون توسط Designer یا کدی که اجرا میشه، ارجاع هایی که به اون کنترل یا اشیاء مرتبط می دهید بی اعتبار بشه و سراغ اشیاء ای که null شدن یا Dispose شدن نرید. بی اعتبار شدن کنترل صرفا نابودی شیء اش نیست، اگر Dispose بشه و منابعی مثل Handle پنجره ازش گرفته بشه هم بی اعتبار ئه، با وجود اینکه حافظه Managed اش همچنان سرجاش هست.

بعد اینکه بعضی وقت ها که این کنترل TransparentControl را توی فرم اضافه میکنم ، دیزاینر فرم ، قاتی میکنه و همون ارور معروف رو میده (که دیگه صفحه ی دیزاینر در دسترس قرار نمیگیره . اما موقع اجرا ، مشکلی نداره) اما وقتی ویژال استودیو را ببندم و دوباره وارد پروژه ام بشم ، انگار مشکل حل میشه. چرا؟
کلا زیاد با صفحه ی دیزاینر ویژال استودیو سازگار نیست (البته مشکل نمایش کنترل رو نداره . فقط این مشکلاتی که گفتم را داره) . چرا؟ میشه کاریش کرد که این مشکلات را نداشته باشه؟
معمولا مربوط به توقف اجرای روتین و خطاهایی است که میان اجرای کد بوجود میاد و کاری که باید تا انتها انجام بشه نمیشه و گاهی هم ازشون بی خبرید.
بخاطر بسپارید که Designer اگر کاری رو به دلیل اشکال کدتون کامل انجام نده ممکنه پیام خطایی هم نشون نده.
موقع اجرای کد الزاما شما متوجه همه خطا ها نخواهید شد، مخصوصا خطاهایی که موقع فراخوانی اولیه فرم و برنامه اتفاق می افتند و با try catch بدام نیافتاده اند، ممکن است اصلا به شما اطلاع داده نشوند ولی در نتیجه اجرا تاثیر بذارند.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
ارجاع هایی که به اشیاء میدهید رو بررسی کنید. اگر قرار است به مشخصه های شیء ای رجوع کنید هم باید مطمئن شوید که در آن لحظه null نیست و هم اگر مشخصه مربوط به ظاهر کنترل ئه، کنترل Handle داره و نابود نشده.
شما باید در هر زمان آمادگی این رو داشته باشید که با نابود شدن شیء کنترل تون توسط Designer یا کدی که اجرا میشه، ارجاع هایی که به اون کنترل یا اشیاء مرتبط می دهید بی اعتبار بشه و سراغ اشیاء ای که null شدن یا Dispose شدن نرید. بی اعتبار شدن کنترل صرفا نابودی شیء اش نیست، اگر Dispose بشه و منابعی مثل Handle پنجره ازش گرفته بشه هم بی اعتبار ئه، با وجود اینکه حافظه Managed اش همچنان سرجاش هست.

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


معمولا مربوط به توقف اجرای روتین و خطاهایی است که میان اجرای کد بوجود میاد و کاری که باید تا انتها انجام بشه نمیشه و گاهی هم ازشون بی خبرید.
بخاطر بسپارید که Designer اگر کاری رو به دلیل اشکال کدتون کامل انجام نده ممکنه پیام خطایی هم نشون نده.
موقع اجرای کد الزاما شما متوجه همه خطا ها نخواهید شد، مخصوصا خطاهایی که موقع فراخوانی اولیه فرم و برنامه اتفاق می افتند و با try catch بدام نیافتاده اند، ممکن است اصلا به شما اطلاع داده نشوند ولی در نتیجه اجرا تاثیر بذارند.

این هم کلی بود . بصورت جزئی نمیدونم چی کار باید کرد .
خیلی ممنون
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
ارجاع هایی که به اشیاء میدهید رو بررسی کنید. اگر قرار است به مشخصه های شیء ای رجوع کنید هم باید مطمئن شوید که در آن لحظه null نیست و هم اگر مشخصه مربوط به ظاهر کنترل ئه، کنترل Handle داره و نابود نشده.
شما باید در هر زمان آمادگی این رو داشته باشید که با نابود شدن شیء کنترل تون توسط Designer یا کدی که اجرا میشه، ارجاع هایی که به اون کنترل یا اشیاء مرتبط می دهید بی اعتبار بشه و سراغ اشیاء ای که null شدن یا Dispose شدن نرید. بی اعتبار شدن کنترل صرفا نابودی شیء اش نیست، اگر Dispose بشه و منابعی مثل Handle پنجره ازش گرفته بشه هم بی اعتبار ئه، با وجود اینکه حافظه Managed اش همچنان سرجاش هست.

سلامی مجدد
آها متوجه شدم . باید بصورت کدنویسی ، کنترل مو dispose میکردم و این مشکل پیش میومد تا ببینم مشکل از کجاست .
مشکل از کد داخل متد OnParentChanged بود که درست شد.
خیلی ممنون


معمولا مربوط به توقف اجرای روتین و خطاهایی است که میان اجرای کد بوجود میاد و کاری که باید تا انتها انجام بشه نمیشه و گاهی هم ازشون بی خبرید.
بخاطر بسپارید که Designer اگر کاری رو به دلیل اشکال کدتون کامل انجام نده ممکنه پیام خطایی هم نشون نده.
موقع اجرای کد الزاما شما متوجه همه خطا ها نخواهید شد، مخصوصا خطاهایی که موقع فراخوانی اولیه فرم و برنامه اتفاق می افتند و با try catch بدام نیافتاده اند، ممکن است اصلا به شما اطلاع داده نشوند ولی در نتیجه اجرا تاثیر بذارند.

اما این قضیه را هنوز کامل و دقیق متوجه نشدم . البته همیشه این اتفاق نمیافته.
خیلی ممنون استاد علی :rose:
 

the_king

مدیرکل انجمن
سلام
خیلی ممنون استاد
من واضح متوجه نشدم . اگه امکان داره ، در مقیاس بسیار ساده و ساده ، یه مثال میتونین بزنین که دقیقا به عنوان مثال ، چه نوع کدی را در کدوم تابع یا رویداد باید نوشت تا موقع حذف اون کنترل از دیزاینر ، اون ارور را نده؟
درست برعکسه، قرار نیست در رویداد خاصی کدی نوشته بشه، باید کدهاتون که ایراد داره رو اصلاح کنید. شما اگر کدی ننویسید که سراغ اشیاء غیر قابل دسترس بره که خطایی بوجود نمیاد.
دلیل خطا کدی است که شما بدون توجه به شرایط دسترسی می نویسید، انگار که فرض رو بر این گرفتید که اشیاء ویژوال در همه لحظات در دسترس هستند، در حالی که واقعا نیستند.
روتین هایی که می نویسید رو در try catch قرار بدید تا محلی که ایراد داره مشخص بشه. از MessageBox استفاده نکنید، Breakpoint قرار بدید.
breakpoint.png

این هم کلی بود . بصورت جزئی نمیدونم چی کار باید کرد .
خیلی ممنون
باید هم کلی باشه، شما در هر کدی و در هر برنامه ای باید حواستون به این باشه که شیء ای که بهش رجوع می کنید در دسترس باشه. تا حالا از ReSharper استفاده کرده اید؟ ممکنه بعضی پروژه های بزرگ رو کند کنه یا ایراد های بنی اسرائیلی بگیره ولی در کل کمک تون می کنه که اصولی تر کد نویسی کنید. یک مدت که به رعایت مواردی که بهشون ایراد می گیره عادت کنید دیگه کمتر بهش نیاز پیدا خواهید کرد.
یک مثال کوچیک بزنم، بر مبنای کدی که در پیوست transparentcontrol.rar پست 1320# داشتید. فرضا یک همچین کدی رو داریم :
کد:
        private void Form1_Load(object sender, EventArgs e)
        {
            var ct = new TransparentControlText("Text");
            var t = new TransparentControl(ct, Point.Empty);
            t.Parent = this;
            t.Parent = null;
        }
خیلی منطقی است که Parent میتونه null باشه، ولی مهم اینه که مطمئن باشید که در OnParentChanged به این مساله بقدر کافی توجه شده. البته این صرفا یک مثاله.
تمامی اشیاء که ممکنه است null باشند یا Dispose شده باشن باید قبل از دسترسی بهشون بررسی بشن. یک قاعده کلی ئه. صحبت هیچ رخداد و روتین خاصی نیست.
در اجرای کد بالا به ظاهر هم خطایی دریافت نمیشه. اما به این معنا نیست که کد ایرادی نداره. خطایی دریافت نمیشه، چون در مرحله فراخوانی شدن فرم، Designer ویژوال استدیو تمایلی به بروز همه خطاها نداره،
پنهان کردن خطا رو بخاطر بدجنسی نمی کنه، اینکار رو نمی کنه چون اگر بخواد خطا رو اعلام کنه، روتین فراخوانی فرم نیمه کاره متوقف میشه و احتمال از دست رفتن داده های محیط ویژوال فرم و کمپوننت های درون اون زیاده.
اگر همون کد رو بجای داخل Form.Load برای Click یک دکمه می نوشتیم، معلوم میشد که دسترسی به ControlAdded اون Parent ای که null شده کار درستی نبوده :
کد:
        private void button1_Click(object sender, EventArgs e)
        {
            var ct = new TransparentControlText("Text");
            var t = new TransparentControl(ct, Point.Empty);
            t.Parent = this;
            t.Parent = null;
        }
breakpoint2.png
یکی از مزایای ReSharper برای شما در اینه که با بررسی کدتون کمک می کنه که اینجور کد هایی مثل controlParent.ControlAdded رو بدون بررسی اولیه که آیا controlParent مقدار null داره یا نه ننویسید.
اوایل که بهش عادت ندارید سخته چون ممکنه خیلی از کد نویسی تون ایراد بگیره، ولی ارزشش داره، چون کم کم عادت می کنید که اول وضعیت اشیاء رو چک کنید و بعد سراغشون برید.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
اینکه بخاطر تجربیات قبلی تون همچین دیدی به نخ ها پیدا کنید طبیعیه چون تا به حال همچین رفتاری ازشون دیده بودید و تازه الانه که به نظرتون رفتارشون متفاوت بوده، اما در نظر بگیرید که اولا همزمانی نخ ها در اغلب اوقات یک مفهوم ظاهری و شبیه سازی شده است، چون در سیستمی که بصورت فیزیکی فرضا نهایتا در مجموع 16 نخ میتوانست در کل هسته ها اجرا بشه، صدها پروسه و هزاران نخ در حال اجرا هستند، که مدام بین نخ ها سوئیچ میشه و در بیشتر موارد واقعا همزمانی لحظه ای در کار نیست و فقط به نظر میاد که همزمان اجرا میشن.
ثانیا نخ هایی که شما میسازید، یک شیء نرم افزاری و کاملا مجازی هستند، شما اون چند تا شاخه اجرایی در هسته رو مستقیم تحت کنترل ندارید و توقف نخ شما به این معنی نیست که یک بخش اجرایی از هسته دیگه بخواب بره، فوری میره سراغ یک عملیات دیگری که در صف انتظار برای اجرا شدن قرار داره.
ثالثا مدیریت Task ها مثل مدیریت حافظه Managed بهینه سازی شده و هوشمندانه است تا از منابع سیستم در حدی که توانش هست به بهترین شکل استفاده کنه. خیلی عادیه که در شرایطی که نیازی به نخ جدید نباشه از همون نخ های قبلی در دسترس برای اجرا شدن عملیاتی استفاده کنه. اگر شما n تا Task برای اجرا شدن دارید با توجه به ترتیب و نوبت اجرا ممکنه با n - m نخ کارشون رو راه بیاندازه.
رابعا ساختار فرم ها و اساس طراحی سیستم عاملی مثل ویندوز بر رخداد ها است، اگر رخدادی اتفاق بیافته، در صف قرار میگیره تا نوبت اجرا شدنش بشه. همونطور که وقتی شما در یک سیستم کند و به شدت مشغول سریع تایپ می کنید یا با ماوس جایی کلیک می کنید، رخداد های مربوط به تعامل شما اونطور در صف منتظر باقی میمونند که نخ فرصت پاسخگویی بهشون رو پیدا کنه. برای همینه که رخدادی مثل Timer.Tick میتونه در زمانی که روتین شما با await معطل شده اجرا بشه. شما با await نخ رو به خواب نمی برید، نخ رو برای اجرای روتین تون منتظر نگه میدارید که شرایط متفاوتی با بخواب رفتن نخ داره.


خیلی از کلمات در ترجمه معنی های متفاوتی دارند که همه معنی ها برای همه کاربرد ها مناسب نیست و از برخی شون برداشتی می کنید که با منظور اصلی متفاوته.
Synchronous رو همگام معنی کنید بهتره، نه همزمان. منظور از همگام اینکه مستقل از هم کار نمی کنند، با هم هماهنگ و همگام هستند. مثل دو تا دستور در روتین تون که پشت سر هم اجرا میشوند، مثل عملیات Cut و Paste کردن فایل که اول باید Cut انجام بشه و بعد Paste.
اما Asynchronous یعنی ناهمگام، یعنی بین شون هماهنگی در کار نیست، شروع و پایان شون لازم نیست با هم هماهنگ بشه. فرضا برنامه هایی که همزمان که در حال کار عادی برای کاربرشون هستند، نسخه جدید شون رو هم از اینترنت پیدا می کنند و دانلود می کنند، هیچ نیازی هم به هماهنگ کردن این دو کارشون نیست.


نه. فرق داره. await نخ شما رو بخواب نمی برد و می توانست به کار دیگری برسه، اما Task.Wait همونجا نخ رو بخواب میبره و دیگه نخ اجرا کننده نمیتونه هیچ فعالیت دیگری داشته باشه.


سلامی مجدد
الان به مباحث async و await که قبلا هم جواب داده بودین ، داشتم مروری میکردم.ببینید درسته میگم؟ : (البته همون مباحث هه و میخوام فقط مرور کنم)
پس کلا این قضیه اش این جوری هست که فقط در اون متد (یا رویدادی) که کلمه ی کلیدی "await" بکار رفته شده ، کدهایی که قبل از این کلمه ی کلیدی اجرا میشن ، در همون نخِ جاری (که مثلا نخ اصلی را در نظر میگیریم) اجرا میشن . به این کلمه ی کلیدی که میرسه ، کدهای task ، در نخِ جدیدی اجرا میشن (فرض میکنیم هنوز کدهای داخلِ متدِ task تمام نشده) و بنابراین نکته ی مهم اینه که در همین لحظه ، نخ قبلی (نخِ اصلی که فرض کرده بودیم) ، بدون اینکه ادامه ی کدش اجرا بشه ، کدهای صف ها و رویدادهای دیگه را درون نخ اصلی اجرا میکنه . هر وقت که کدهای task (که داخلِ نخِ جدیدی قبلا اجرا شده بود) ، تموم شد ، برمیگرده و ادامه ی کدهای بعد از کلمه ی کلیدی"await" را داخلِ نخِ اصلی مون اجرا میکنه.
حالا چه میخواد توی متدی ، این کلمه ی کلیدی "await" را گذاشته باشیم یا حتی توی رویدادی.

بالاخره ، مهم اینه که در همون نخِ جاری (نخِ اصلی) ، روندِ اجرای کد ، مثل حالتِ عادی طی میشه (یعنی بدون اینکه در کد await ای نوشته باشیم) منتها فقط و فقط ، کدهای زیرِ await ، اجرا نمیشن (بلکه بقیه ی رویدادها و متدها ، حتی با اجرای await هم پاسخگو هستند و اجرا میشن) (البته بجز اینکه تسک ای که به await میدیم ، داخلِ نخِ جدیدی اجرا میشه). به عبارت دیگه ، این قضیه ی async و await ، دقیقا کارِ همون System.Threading.Thread را انجام میده با این تفاوت که فقط کدهای زیرِ await تا زمانی که کدهای task مون تمام نشدن ، درون نخ اصلی اجرا نمیشن.
البته ، await ، اولا شیِ Task میگیره و دوما باید اجرا شده باشه . یعنی قبل از اینکه کلمه ی await را بکار ببریم ، باید از متدِ Start از درون شی task استفاده کنیم (که مثال کلی را قبلا گفتید) :

کد:
        public Page4(Form form) : base(form)
        {
            InitializeComponent();
          
            //////////////////////////////////////////////
          
            this.InitializeMyControls();

        }



        private async void InitializeMyControls()
        {
            MessageBox.Show("AsyncAway_1 main thread before  =  " + Thread.CurrentThread.ManagedThreadId);
            var task = new Task<int>(this.AsyncAway_2);
            task.Start();
            int taskWait = await task;
            MessageBox.Show("AsyncAway_1 main thread after  =  " + Thread.CurrentThread.ManagedThreadId);
        }



        private int AsyncAway_2()
        {
            MessageBox.Show("AsyncAway_2 thread  =  " + Thread.CurrentThread.ManagedThreadId);
            return 7 * 7;
        }

        private void Page4_Load(object sender, EventArgs e)
        {
            MessageBox.Show("Page4_Load");
        }

Page4 ، کنترلی از نوعِ user control هست.

---------------------------------------------------------------

اما در کد بالا ، یه چیزی را دقیق درک نکردم . کد int taskWait = await task; رو دقیق متوجه نشدم.
قسمت await task شو متوجه شدم . چون await ، شی ای از task که اونم قبل اش اجرا شده باشه ، میخواد اما چجوری میشه که شیِ task را که شی از نوع Task<T> هست و هیچ رابطه ای با نوعِ T (که در اینجا نوعِ int هست) نداره را توی شی ای از نوع int (همون متغییر taskWait) میریزین و تبدیل هم نمیخواد و ارور هم نمیده؟!
مثلا اگه متغییر Result از شی task را توی شی ای از int میریختین (یعنی int taskWait = task.Result;) ، مشکلی نبود و متوجه میشم اما اونو متوجه نمیشم.
 
آخرین ویرایش:

the_king

مدیرکل انجمن
سلامی مجدد
الان به مباحث async و await که قبلا هم جواب داده بودین ، داشتم مروری میکردم.ببینید درسته میگم؟ : (البته همون مباحث هه و میخوام فقط مرور کنم)
پس کلا این قضیه اش این جوری هست که فقط در اون متد (یا رویدادی) که کلمه ی کلیدی "await" بکار رفته شده ، کدهایی که قبل از این کلمه ی کلیدی اجرا میشن ، در همون نخِ جاری (که مثلا نخ اصلی را در نظر میگیریم) اجرا میشن . به این کلمه ی کلیدی که میرسه ، کدهای task ، در نخِ جدیدی اجرا میشن (فرض میکنیم هنوز کدهای داخلِ متدِ task تمام نشده) و بنابراین نکته ی مهم اینه که در همین لحظه ، نخ قبلی (نخِ اصلی که فرض کرده بودیم) ، بدون اینکه ادامه ی کدش اجرا بشه ، کدهای صف ها و رویدادهای دیگه را درون نخ اصلی اجرا میکنه . هر وقت که کدهای task (که داخلِ نخِ جدیدی قبلا اجرا شده بود) ، تموم شد ، برمیگرده و ادامه ی کدهای بعد از کلمه ی کلیدی"await" را داخلِ نخِ اصلی مون اجرا میکنه.
حالا چه میخواد توی متدی ، این کلمه ی کلیدی "await" را گذاشته باشیم یا حتی توی رویدادی.

تا اینجا درسته.
بالاخره ، مهم اینه که در همون نخِ جاری (نخِ اصلی) ، روندِ اجرای کد ، مثل حالتِ عادی طی میشه (یعنی بدون اینکه در کد await ای نوشته باشیم) منتها فقط و فقط ، کدهای زیرِ await ، اجرا نمیشن (بلکه بقیه ی رویدادها و متدها ، حتی با اجرای await هم پاسخگو هستند و اجرا میشن) (البته بجز اینکه تسک ای که به await میدیم ، داخلِ نخِ جدیدی اجرا میشه).

اینم درسته.
به عبارت دیگه ، این قضیه ی async و await ، دقیقا کارِ همون System.Threading.Thread را انجام میده با این تفاوت که فقط کدهای زیرِ await تا زمانی که کدهای task مون تمام نشدن ، درون نخ اصلی اجرا نمیشن.

نه. async صرفا اعلام می کنه که در این روتین await هایی خواهد بود. await هم فقط انتظار برای پایان اجرای Task ای است، اون بخشی که نخ رو ایجاد می کنه نه async ئه و نه await. قبلا هم گفتم، نخ ساختن در Task انجام شده، await خودش نقشی در نخ ساختن و مدیریت Thread ها نداره، await صرفا اجرای باقی روتین رو منتظر پایان اجرای عملیاتی می کنه، بدون اینکه خود نخ اجرا کننده رو Sleep کنه. دلیل اینکه نخ به سایر رخداد ها پاسخگو میمونه همینه که await کارش توقف اجرای نخ نیست، انتظار رو فقط روی روتین اعمال می کنه تا بقیه کد های روتین اجرا نشن.

اما در کد بالا ، یه چیزی را دقیق درک نکردم . کد int taskWait = await task; رو دقیق متوجه نشدم.
قسمت await task شو متوجه شدم . چون await ، شی ای از task که اونم قبل اش اجرا شده باشه ، میخواد اما چجوری میشه که شیِ task را که شی از نوع Task<T> هست و هیچ رابطه ای با نوعِ T (که در اینجا نوعِ int هست) نداره را توی شی ای از نوع int (همون متغییر taskWait) میریزین و تبدیل هم نمیخواد و ارور هم نمیده؟!
مثلا اگه متغییر Result از شی task را توی شی ای از int میریختین (یعنی int taskWait = task.Result;) ، مشکلی نبود و متوجه میشم اما اونو متوجه نمیشم.
شی task در taskWait ریخته نمیشه، شما که نمی توانید ;int taskWait = await task رو معادل ;int taskWait = task تفسیر کنید. اون await اون وسط باقالی که نیست، جزو کلمات کلیدی زبان ئه، نقش داره.
متوجه نشدنتون بخاطر اینه که کاری به تعریف await در زبان ندارید. بعد اینکه کار عملیات تموم شد و await به توقف پایان داد مقدار بازگشتی اون عملیات رو برمیگردونه.
یعنی در تعریف await مشخص شده که نوع داده ای که با اجرای <Task<TResult برگردونده میشه TResult ئه و با اجرای Task (عملیاتی بدون مقدار بازگشتی) null برگردونده میشه :
As shown in the previous example, if await is applied to the result of a method call that returns a Task<TResult>, then the type of the await expression is TResult. If await is applied to the result of a method call that returns a Task, then the type of the await expression is void.​
await - C# Reference - Microsoft Docs
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
تا اینجا درسته.
اینم درسته.

نه. async صرفا اعلام می کنه که در این روتین await هایی خواهد بود. await هم فقط انتظار برای پایان اجرای Task ای است، اون بخشی که نخ رو ایجاد می کنه نه async ئه و نه await. قبلا هم گفتم، نخ ساختن در Task انجام شده، await خودش نقشی در نخ ساختن و مدیریت Thread ها نداره، await صرفا اجرای باقی روتین رو منتظر پایان اجرای عملیاتی می کنه، بدون اینکه خود نخ اجرا کننده رو Sleep کنه. دلیل اینکه نخ به سایر رخداد ها پاسخگو میمونه همینه که await کارش توقف اجرای نخ نیست، انتظار رو فقط روی روتین اعمال می کنه تا بقیه کد های روتین اجرا نشن.

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


شی task در taskWait ریخته نمیشه، شما که نمی توانید ;int taskWait = await task رو معادل ;int taskWait = task تفسیر کنید. اون await اون وسط باقالی که نیست، جزو کلمات کلیدی زبان ئه، نقش داره.
متوجه نشدنتون بخاطر اینه که کاری به تعریف await در زبان ندارید. بعد اینکه کار عملیات تموم شد و await به توقف پایان داد مقدار بازگشتی اون عملیات رو برمیگردونه.
یعنی در تعریف await مشخص شده که نوع داده ای که با اجرای <Task<TResult برگردونده میشه TResult ئه و با اجرای Task (عملیاتی بدون مقدار بازگشتی) null برگردونده میشه :

await - C# Reference - Microsoft Docs

خیلی ممنون
------------------------
در کد زیر :


کد:
            Brush brush = new SolidBrush(Color.Red);
            Brush brush_2 = brush.Clone() as Brush;
         
            MessageBox.Show(((SolidBrush)brush).Color.Name.ToString() + "\n" + ((SolidBrush)brush_2).Color.Name.ToString());

با توجه به اینکه نمیخوایم براش ها (چه متغییر brush و چه متغییر brush_2) را به نوعِ SolidBrush تبدیل کنیم (فقط میخوایم به نوعِ Brush تبدیل کنیم . چون براش های متفاوتی هر بار ممکنه داده بشه به متغییرbrush) ، چجوری باید با این کد ، براش مون را دقیق تکثیر کنیم؟
در کد بالا ، با اونکه ARGB از brush به brush_2 تکثیر شد اما متغییر brush.Color.Name اش با متغییر brush_2.Color.Name متفاوت هه . چرا؟

بعد اینکه ، شی ای Control ها (فعلا منظورم شی ای از فرزندانش مثل Button و ... نیست) را میشه توی حافظه ی جدیدی کپی کرد؟ بجز اینکه تک تک پروپرتی هاش را کپی کنیم؟
 
آخرین ویرایش:

the_king

مدیرکل انجمن
در کد زیر :

کد:
            Brush brush = new SolidBrush(Color.Red);
            Brush brush_2 = brush.Clone() as Brush;
        
            MessageBox.Show(((SolidBrush)brush).Color.Name.ToString() + "\n" + ((SolidBrush)brush_2).Color.Name.ToString());

با توجه به اینکه نمیخوایم براش ها (چه متغییر brush و چه متغییر brush_2) را به نوعِ SolidBrush تبدیل کنیم (فقط میخوایم به نوعِ Brush تبدیل کنیم . چون براش های متفاوتی هر بار ممکنه داده بشه به متغییرbrush) ، چجوری باید با این کد ، براش مون را دقیق تکثیر کنیم؟
کم پیش میاد که نیازی به تکثیر Brush باشه، تکثیر اش هم که توسط ;()var y = (Brush)x.Clone انجام میشه که اهمیتی هم نداره که x از چه نوع خاصی از Brush ها است، y دقیقا از همون نوع Brush خواهد بود که x ئه.
y یک Brush ئه ولی نوع اش Brush نیست، مثلا ممکنه TextureBrush باشه.
Brush ها انواع مختلفی دارند، مثل SolidBrush یا TextureBrush ولی همگی اون انواع ها Brush هستند، همانطور که Button نمیتونه Control نباشه.
شیء ای که SolidBrush ئه همیشه SolidBrush ئه و همواره Brush محسوب میشه. تبدیل کردن SolidBrush به Brush معنی نداره، SolidBrush نوعی Brush ئه، همونطور که میخک نوعی گیاه ئه، میخک رو که نمیشه به گیاه تبدیل کرد. هر بلایی که SolidBrush سرش بیاد نه از SolidBrush بودن در میاد و نه در Brush بودنش تاثیری میذاره. در سوالتون این مورد جانبی است ولی مهمه.
از طرف دیگه منبعی که Dispose شدنی است باید Dispose بشه، هر چه سریعتر بهتر. اگر شیء ای میسازید که Dispose نمی کنید کدتون ایراد داره.
در کد بالا ، با اونکه ARGB از brush به brush_2 تکثیر شد اما متغییر brush.Color.Name اش با متغییر brush_2.Color.Name متفاوت هه . چرا؟
قبلا هم بهتون گفتم، Brush جزو مواردی است که درست موقع ترسیم ایجاد میشه و بعد ترسیم نابود میشه. مثلا شما الان با رنگ SystemColors.Highlight یک Brush بسازید ممکنه یک رنگ باشه، .تم تون رو عوض کنید با رنگ دیگری Brush ساخته بشه. در سیستم من که تم رنگ ها فرق می کنه یک رنگ دیگه باشه. اون کد رنگی که Brush استفاده کرده معادل کد رنگی SystemColors.Highlight در اون لحظه و در اون سیستم ئه.
تکثیرش هم که بکنید دقیقا همون کد رنگی رو بکار میبره. دیگه کاری نداره که الان و موقع تکثیر SystemColors.Highlight چه کد رنگی ای داره، اگر مجددا SystemColors.Highlight رو تفسیر میکرد، ممکن بود رنگ جدیدی بدست بیاد و رنگ تکثیر شده مثل نسخه اصلی نمیشد. هدف تکثیر اینه که مشابه قبلی بشه، اگه بخواد موقع تکثیر Color رو از نو به کد رنگ ترجمه کنه ممکنه مشابه قبلی نباشه.

یکسری رنگ ها با اسامی شناخته شده وجود دارند، چه رنگ های سیستمی و چه رنگ های معروف تحت وب، اما نهایتا همه این رنگ ها موقع نمایش معادل عددی رنگ ARGB دارند. بعضی هاشون مثل رنگ های سیستمی حتی در تم های مختلف ویندوز رنگ های مختلفی دارند و کد رنگ معادلشون ثابت و از قبل مشخص نیست. همانطور که شما می توانید enum ها رو به عدد تبدیل کنید، این اسامی هم به کد رنگ تبدیل میشوند. با اون کد رنگ می توانید شیء ای با رنگ مشابه بسازید ولی دقیقا همون نیست، رنگش مشابهه. معنی اش این نیست که اون معادل عددی هم خودکار به اسم معادل تبدیل بشه. رنگی که شما با کد رنگ میسازید حتی اگر دقیقا مشابه کد یک رنگ با نام مشخص باشه معادل هم نیستند. مثلا در اغلب ویندوز ها رنگ زمینه TextBox ها سفید ئه، اما توقع نداریم که هر وقت با کد رنگ، رنگ سفید بسازیم معادل Color.White یا SystemColors.Window باشه.
بعد اینکه ، شی ای Control ها (فعلا منظورم شی ای از فرزندانش مثل Button و ... نیست) را میشه توی حافظه ی جدیدی کپی کرد؟ بجز اینکه تک تک پروپرتی هاش را کپی کنیم؟
نه. حافظه جدید در مورد چیزی معنی میده که به نسخه اصلی حافظه دسترسی داشته باشید، شما که به حافظه اون Button دسترسی ندارید. در ضمن گیرم که دسترسی هم داشتید، کپی کردنش به معنی تکثیر یک شیء به دو نسخه که نیست.
یک Control مثل خیلی از اشیاء دیگه بر اساس یک منابعی مثل پنجره تعریف شده، شما با کپی کردن Handle پنجره در یک متغیر جدید که پنجره جدیدی نخواهید داشت، مقدار همون پنجره است، پنجره جدیدی که بهتون نمیده.
اون حافظه در صد تا نسخه هم تکثیر بشه، همچنان یک کنترل ئه با یک شماره Handle یکسان پنجره. تکثیر یک شیء همیشه یک عملیات new ئه، کاری که معمولا با Clone انجام می دهند، یعنی ساختن شیء جدید با مقادیر مشابه. برای کپی کردن مقادیر فیلد ها می توانید از System.Reflection کمک بگیرید که تک تک انجام نشه ولی روال همونه. از طرف دیگه بعضی پروپرتی ها رو میخواهید کپی کنید و بعضی ها رو نمی خواهید. فرضا وقتی Bounds هست دلیلی برای تکثیر Width و Height و Size و Location و ... نیست. در روتین های Clone هم تک تک فیلد ها و مشخصه های مناسب رو مشخص می کنند، فقط اونهایی که لازم هستند، بدون توجه به کارکردشون همگی شامل تکثیر نمیشن.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
خیلی ممنون استاد علی از توضیحات تون . البته خلاصه هم توضیح بدین ، برام کافیه . بعضی از مسائل مثل همون گیاه و ... را میدونم .
یه سئوال اینکه ، در بعضی از پروپرتی هایی که درون پنجره ی طراحیِ Properties در ویژال استودیو هستند ، میبینیم که کنارشون یه چیز(آیکون) کوچیکی داره که بزنیم ، مثلا یه پنجره (یا فرم) باز میشه برای مقدار دادن به اعضای اون کلاس . مثل پروپرتی Font و ... .
من اگه بخوام در صفحه ی طراحی ، برای پروپرتیِ TransparentControlBitmap و همچنین برای TransparentControlText ام (که درون کلاس TransparentControl هستند) همچین کاری بکنم و براشون فرم طراحی کنم ، شدنی هست؟ اگه آره ، روالِ کلی اش چجوری هه؟
 

the_king

مدیرکل انجمن
خیلی ممنون استاد علی از توضیحات تون . البته خلاصه هم توضیح بدین ، برام کافیه . بعضی از مسائل مثل همون گیاه و ... را میدونم .
تمایلی به توضیحات اضافه ندارم، اما اگر جملاتی رو بگید که مفهوم اشتباهی رو برسونه ناچارم توضیح بدم، چه منظورتون همون مفهوم باشه یا نه.

یه سئوال اینکه ، در بعضی از پروپرتی هایی که درون پنجره ی طراحیِ Properties در ویژال استودیو هستند ، میبینیم که کنارشون یه چیز(آیکون) کوچیکی داره که بزنیم ، مثلا یه پنجره (یا فرم) باز میشه برای مقدار دادن به اعضای اون کلاس . مثل پروپرتی Font و ... .
من اگه بخوام در صفحه ی طراحی ، برای پروپرتیِ TransparentControlBitmap و همچنین برای TransparentControlText ام (که درون کلاس TransparentControl هستند) همچین کاری بکنم و براشون فرم طراحی کنم ، شدنی هست؟ اگه آره ، روالِ کلی اش چجوری هه؟
یه عالمه کلاس و اینترفیس در System.ComponentModel.Design هست که در ویژوال استدیو برای اختصاصی کردن محیط Designer پشتیبانی میشه که هر کدوم ساختنش قاعده خاص خودش رو داره و در طراحی کمپوننت ها و کنترل ها ازش استفاده می کنند. یکی شون همون قابلیت ئه که برای ویرایش کردن یک نوع داده خاص ویرایشگر اختصاصی طراحی کنید که در پنجره Properties بکار برده بشه. به این ترتیب که در یک کلاس جدید خودتون که کارش ویرایش کردن ئه، اینترفیسی بر اساس کلاس UITypeEditor پیاده سازی می کنید که بتونه نوع داده دلخواه x رو به شیوه مورد نظر شما ویرایش کنه. همانطور که مثلا DateTimeEditor میتونه تاریخ رو ویرایش کنه. حالا در تعریف مشخصه ای که از نوع اون x ئه از صفت Editor (همون EditorAttribute) استفاده می کنید تا بگید ویرایشگر ویژوال این مشخصه باید اون کلاس شما باشه. کلا System.ComponentModel.Design و System.ComponentModel از اینجور قابلیت ها که ویرایشگر و منو و مبدل و ... میسازند زیاد داره.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
تمایلی به توضیحات اضافه ندارم، اما اگر جملاتی رو بگید که مفهوم اشتباهی رو برسونه ناچارم توضیح بدم، چه منظورتون همون مفهوم باشه یا نه.


یه عالمه کلاس و اینترفیس در System.ComponentModel.Design هست که در ویژوال استدیو برای اختصاصی کردن محیط Designer پشتیبانی میشه که هر کدوم ساختنش قاعده خاص خودش رو داره و در طراحی کمپوننت ها و کنترل ها ازش استفاده می کنند. یکی شون همون قابلیت ئه که برای ویرایش کردن یک نوع داده خاص ویرایشگر اختصاصی طراحی کنید که در پنجره Properties بکار برده بشه. به این ترتیب که در یک کلاس جدید خودتون که کارش ویرایش کردن ئه، اینترفیسی بر اساس کلاس UITypeEditor پیاده سازی می کنید که بتونه نوع داده دلخواه x رو به شیوه مورد نظر شما ویرایش کنه. همانطور که مثلا DateTimeEditor میتونه تاریخ رو ویرایش کنه. حالا در تعریف مشخصه ای که از نوع اون x ئه از صفت Editor (همون EditorAttribute) استفاده می کنید تا بگید ویرایشگر ویژوال این مشخصه باید اون کلاس شما باشه. کلا System.ComponentModel.Design و System.ComponentModel از اینجور قابلیت ها که ویرایشگر و منو و مبدل و ... میسازند زیاد داره.

خیلی ممنون استاد .
من خیلی متوجه نشدم :green:
فقط کلاس ImageEditor را متوجه شدم انگار دیالوگ Open File را برای انتخاب فایل برای تصویر باز میکنه .
اول بگین کلا روند این کار خیلی طول میکشه؟ چون نمیخوام زیاد واسش وقت بذارم . اصلا هم قرار نبود واسه ی این کنترل ، این قدر وقت بذارم ولی گفتم نسخه ی اولیه شو که ارائه دادم ، بذار قابلیت هایی بهش اضافه کنم که به یک کنترل استاندارد برسه که هر کس بتونه ازش استفاده کنه جوری که قابلیت مانور نسبی داشته باشه.
اگه خیلی طول نمیکشه ، و اگه زحمت تون نیست (اگه زحمت تون میشه ، نمیخواد) ، میتونین یه مثال در مقیاس بسیار کوچیک بزنین که یه کنترلی دارین (یه کلاسی که از کلاس Control ارث بری کنه) که این کلاس ، فقط یک پروپرتی داره و این پروپرتی را که کاربر از محیط ویژال استودیو انتخاب میکنه ، یه شی ای از کلاس فرم براش باز کنه. نمیدونم حالا سختی اش در چه حده.
 

the_king

مدیرکل انجمن
خیلی ممنون استاد .
من خیلی متوجه نشدم :green:
چی رو متوجه نشدید؟ یک کلاس میسازید برای ویرایشگر. کلاس اش هم که راهنما داره و نمونه مثال.
فقط کلاس ImageEditor را متوجه شدم انگار دیالوگ Open File را برای انتخاب فایل برای تصویر باز میکنه .
اول بگین کلا روند این کار خیلی طول میکشه؟ چون نمیخوام زیاد واسش وقت بذارم . اصلا هم قرار نبود واسه ی این کنترل ، این قدر وقت بذارم ولی گفتم نسخه ی اولیه شو که ارائه دادم ، بذار قابلیت هایی بهش اضافه کنم که به یک کنترل استاندارد برسه که هر کس بتونه ازش استفاده کنه جوری که قابلیت مانور نسبی داشته باشه.
برای کوچکترین کارها هم می توانید زمان زیادی صرف کنید، هر کسی خودشو بهتر میشناسه. من نمیتونم بگم برای شما چقدر طول میکشه، صرفا میتونم بگم روالش کار بزرگی نیست.
زمانی که طول میکشه صرفا به خودتون بستگی داره.
اگه خیلی طول نمیکشه ، و اگه زحمت تون نیست (اگه زحمت تون میشه ، نمیخواد) ، میتونین یه مثال در مقیاس بسیار کوچیک بزنین که یه کنترلی دارین (یه کلاسی که از کلاس Control ارث بری کنه) که این کلاس ، فقط یک پروپرتی داره و این پروپرتی را که کاربر از محیط ویژال استودیو انتخاب میکنه ، یه شی ای از کلاس فرم براش باز کنه. نمیدونم حالا سختی اش در چه حده.
لینکش رو قرار دادم، خودش مثال داره. اگر جستجو کنید مثال های بهتری هم هست. برای کلاس خودتون بجای UITypeEditorEditStyle.DropDown نوع UITypeEditorEditStyle.Modal رو انتخاب می کنید تا بگید میخواهید بجای ویرایش در PropertyGrid، یک فرم ویرایشگر جداگانه ای باز بشه، خود کلاسش فرمی نداره و فرم باز نمی کنه، خودتون یک فرمی رو باز می کنید و نمایش میدید. دیگه اینکه در متد EditValue چه فرمی رو باز کنید و چه کاری انجام بدید بستگی به خودتون داره.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
چی رو متوجه نشدید؟ یک کلاس میسازید برای ویرایشگر. کلاس اش هم که راهنما داره و نمونه مثال.

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

لینکش رو قرار دادم، خودش مثال داره. اگر جستجو کنید مثال های بهتری هم هست. برای کلاس خودتون بجای UITypeEditorEditStyle.DropDown نوع UITypeEditorEditStyle.Modal رو انتخاب می کنید تا بگید میخواهید بجای ویرایش در PropertyGrid، یک فرم ویرایشگر جداگانه ای باز بشه، خود کلاسش فرمی نداره و فرم باز نمی کنه، خودتون یک فرمی رو باز می کنید و نمایش میدید. دیگه اینکه در متد EditValue چه فرمی رو باز کنید و چه کاری انجام بدید بستگی به خودتون داره.

سلامی مجدد
آها خیلی ممنون استاد
منظورتون این بود که همون مثالی که زد ، دیگه نیاز به کار چندان خاص و ویرایش خاصی نداره و همونو کپی کنم.
در کد زیر (متد EditValue درون کلاس UITypeEditor که در کلاس فرزندش بازنویسی شد) :


کد:
        public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
        {
            // اگر مقدار value ، همون از نوع TransparentControlBitmap نبود ، ادامه نده.
            TransparentControlBitmap currentTranspControlBitmap = value as TransparentControlBitmap;
            if (currentTranspControlBitmap == null)
                return value;

            // برای نمایش فرم TransparentControlBitmapEditorForm مون ، لازم داریم provider را به نوعِ IWindowsFormsEditorService تبدیل کنیم.
            IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
            if (edSvc != null)
            {
                // اول شی ای از فرم TransparentControlBitmapEditorForm برای نمایش بسازه و مقدارِ جاریِ پروپرتی TransparentControl.TransparentControlBitmap را برایش در متد سازنده ی این کلاس توسط value ، ارسال کنه و بعد فرم را به نمایش بذاره تا برنامه نویس از صفحه ی فرم برای ویرایش مقادیر ، استفاده کنه.
                TransparentControlBitmapEditorForm transCtrlBtmpEditorForm = new TransparentControlBitmapEditorForm(ref currentTranspControlBitmap);
                edSvc.ShowDialog(transCtrlBtmpEditorForm);

                MessageBox.Show(currentTranspControlBitmap.Equals(transCtrlBtmpEditorForm.CurrentAutoScaleDimensions).ToString());
                // مقدار بازگشتی TransparentControlBitmap که بعد از اتمامِ صفحه ی طراحی ، برای پروپرتیِ TransparentControl.TransparentControlBitmap ست میشه.
                return currentTranspControlBitmap;
            }
            return value;
        }

و همچنین کلاس فرم برای زمان ویرایش :


کد:
    internal class TransparentControlBitmapEditorForm : Form
    {
        private TransparentControlBitmap CurrentTransparentControlBitmap { get; set; }
        internal TransparentControlBitmapEditorForm(ref TransparentControlBitmap currentTranspControlBitmap)
        {
            this.CurrentTransparentControlBitmap = currentTranspControlBitmap;
        }
        }
    }

من الان میخوام درون متد EditValue ، متغییر currentTranspControlBitmap که همون مقدار جاریِ value (که از نوع TransparentControlBitmap هست) توش ذخیره شد را بعد از تغییرات در فرم ، همون شی را برگردونم . اما همونطور که میبینین ، بعد از بستن فرم ، میگه اشاره گرِ این دو شی currentTranspControlBitmap.Equals(transCtrlBtmpEditorForm.CurrentAutoScaleDimensions) با هم برابر نیست.
چرا؟
با اونکه هم بصورت ref ارسال کردم . ref را هم برداشتم ، باز هم همون بود .
غیر از اینه که متغییرهای value و currentTranspControlBitmap و پروپرتی CurrentTransparentControlBitmap (در کلاس TransparentControlBitmapEditorForm) ، به یه شی اشاره میکنن؟
کلا میخوام اشاره گرِ currentTranspControlBitmap را بفرستم و همون اشاره گر را در متد EditValue برگردونم . چی کار باید کنم؟
با تشکر

کل کد رو اگه بخواین :


کد:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using CustomControl.Transparent;
using System.Security.Permissions;
using System.Drawing.Drawing2D;


namespace CustomControl.PropertiesEditor
{
    /// <summary>
    /// این کلاس ، برای ارسال و نمایشِ کلاس TransparentControlBitmapEditorForm و همچنین مقدارِ بازگشتیِ این کلاس ، در زمانِ طراحی (درون پنجره ی Properties مربوط به پروپرتی TransparentControlBitmap) هست .
    /// </summary>
    [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
    public class TransparentControlBitmapEditor : UITypeEditor
    {
        /// <summary>
        /// با مقدارِ بازگشتیِ این متد ، مشخص میکنیم که در پنجره ی Properties ، درون کادری که مربوط به مقداردهی پروپرتیِ مورد نظرمون هست (در اینجا پروپرتیِ  TransparentControlBitmap ، در سمتِ راستِ کادر ، چه نوع علامتی نشون داده بشه.
        /// </summary>
        /// <param name="context"></param>
        /// <returns>
        /// با مقدارِ بازگشتیِ این متد ، مشخص میکنیم که در پنجره ی Properties ، درون کادری که مربوط به مقداردهی پروپرتیِ مورد نظرمون هست (در اینجا پروپرتیِ  TransparentControlBitmap ، در سمتِ راستِ کادر ، چه نوع علامتی نشون داده بشه.
        /// </returns>
        public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
        {
            // گزینه ی UITypeEditorEditStyle.Modal مشخص میکنه که در پنجره ی Properties ، درون کادری که مربوط به مقداردهی پروپرتیِ مورد نظرمون هست (در اینجا پروپرتیِ  TransparentControlBitmap ، در سمتِ راستِ کادر ، علامتِ سه نقطه رو نشون بده.
            // برای نشون دادن فرم ، درون متد EditValue باید کدِ زیر را بنویسیم و متدِ edSvc.ShowDialog اش را اجرا کنیم.
            // IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));

            return UITypeEditorEditStyle.Modal;
        }

        /// <summary>
        /// زمانی این متد اجرا میشه که برنامه نویس درون پنجره ی Properties درون ویژال استودیو ، میخواد مقدار پروپرتی مورد نظر که در اینجا همون پروپرتی TransparentControlBitmap هست را تغییر بده . یعنی کنار اون دکمه ، کلیک کرد.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="provider"></param>
        /// <param name="value">
        /// مقدار جاریِ TransparentControlBitmap ، در این پارامتر ریخته میشه.
        /// </param>
        /// <returns>
        /// مقدارِ بازگشتیِ این تایع ، مقدارِ آخرِ پروپرتیِ مورد نظرمون (در اینجا پروپرتیِ TransparentControlBitmap را ست میکنه
        /// </returns>
        public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
        {
            // اگر مقدار value ، همون از نوع TransparentControlBitmap نبود ، ادامه نده.
            TransparentControlBitmap currentTranspControlBitmap = value as TransparentControlBitmap;
            if (currentTranspControlBitmap == null)
                return value;

            // برای نمایش فرم TransparentControlBitmapEditorForm مون ، لازم داریم provider را به نوعِ IWindowsFormsEditorService تبدیل کنیم.
            IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
            if (edSvc != null)
            {
                // اول شی ای از فرم TransparentControlBitmapEditorForm برای نمایش بسازه و مقدارِ جاریِ پروپرتی TransparentControl.TransparentControlBitmap را برایش در متد سازنده ی این کلاس توسط value ، ارسال کنه و بعد فرم را به نمایش بذاره تا برنامه نویس از صفحه ی فرم برای ویرایش مقادیر ، استفاده کنه.
                TransparentControlBitmapEditorForm transCtrlBtmpEditorForm = new TransparentControlBitmapEditorForm(ref currentTranspControlBitmap);
                edSvc.ShowDialog(transCtrlBtmpEditorForm);

                MessageBox.Show(currentTranspControlBitmap.Equals(transCtrlBtmpEditorForm.CurrentAutoScaleDimensions).ToString());
                // مقدار بازگشتی TransparentControlBitmap که بعد از اتمامِ صفحه ی طراحی ، برای پروپرتیِ TransparentControl.TransparentControlBitmap ست میشه.
                return currentTranspControlBitmap;
            }
            return value;
        }

        /// <summary>
        /// این متد ، درون کادرِ پروپرتی مورد نظر (پروپرتیِ TransparentControl.TransparentControlBitmap ) ، در سمت چپ اش ، آیکونی با این شکلی که درونِ این متد مینویسسم را رسم میکنه.
        /// </summary>
        /// <param name="e"></param>
        public override void PaintValue(PaintValueEventArgs e)
        {
            using (Pen pen = new Pen(Color.White, 1))
            {
                e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
                e.Graphics.DrawEllipse(pen, new Rectangle(new Point(2, 2), new Size(e.Bounds.Size.Width - 3, e.Bounds.Size.Height - 3)));
            }
        }

        /// <summary>
        /// مشخص میکنه که آیا شکل ای که در متدِ PaintValue تعیین کردیم ، درون کادرِ پروپرتی مورد نظر (پروپرتیِ TransparentControl.TransparentControlBitmap ) ، در سمت چپ اش ، رسم بشه یا نشه..
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public override bool GetPaintValueSupported(ITypeDescriptorContext context)
        {
            return true;
        }
    }


    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    internal class TransparentControlBitmapEditorForm : Form
    {
        private TransparentControlBitmap CurrentTransparentControlBitmap { get; set; }
        internal TransparentControlBitmapEditorForm(ref TransparentControlBitmap currentTranspControlBitmap)
        {
            this.CurrentTransparentControlBitmap = currentTranspControlBitmap;
        }

    }

}
 

the_king

مدیرکل انجمن
سلامی مجدد
آها خیلی ممنون استاد
منظورتون این بود که همون مثالی که زد ، دیگه نیاز به کار چندان خاص و ویرایش خاصی نداره و همونو کپی کنم.
در کد زیر (متد EditValue درون کلاس UITypeEditor که در کلاس فرزندش بازنویسی شد) :


کد:
        public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
        {
            // اگر مقدار value ، همون از نوع TransparentControlBitmap نبود ، ادامه نده.
            TransparentControlBitmap currentTranspControlBitmap = value as TransparentControlBitmap;
            if (currentTranspControlBitmap == null)
                return value;

            // برای نمایش فرم TransparentControlBitmapEditorForm مون ، لازم داریم provider را به نوعِ IWindowsFormsEditorService تبدیل کنیم.
            IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
            if (edSvc != null)
            {
                // اول شی ای از فرم TransparentControlBitmapEditorForm برای نمایش بسازه و مقدارِ جاریِ پروپرتی TransparentControl.TransparentControlBitmap را برایش در متد سازنده ی این کلاس توسط value ، ارسال کنه و بعد فرم را به نمایش بذاره تا برنامه نویس از صفحه ی فرم برای ویرایش مقادیر ، استفاده کنه.
                TransparentControlBitmapEditorForm transCtrlBtmpEditorForm = new TransparentControlBitmapEditorForm(ref currentTranspControlBitmap);
                edSvc.ShowDialog(transCtrlBtmpEditorForm);

                MessageBox.Show(currentTranspControlBitmap.Equals(transCtrlBtmpEditorForm.CurrentAutoScaleDimensions).ToString());
                // مقدار بازگشتی TransparentControlBitmap که بعد از اتمامِ صفحه ی طراحی ، برای پروپرتیِ TransparentControl.TransparentControlBitmap ست میشه.
                return currentTranspControlBitmap;
            }
            return value;
        }

و همچنین کلاس فرم برای زمان ویرایش :


کد:
    internal class TransparentControlBitmapEditorForm : Form
    {
        private TransparentControlBitmap CurrentTransparentControlBitmap { get; set; }
        internal TransparentControlBitmapEditorForm(ref TransparentControlBitmap currentTranspControlBitmap)
        {
            this.CurrentTransparentControlBitmap = currentTranspControlBitmap;
        }
        }
    }

من الان میخوام درون متد EditValue ، متغییر currentTranspControlBitmap که همون مقدار جاریِ value (که از نوع TransparentControlBitmap هست) توش ذخیره شد را بعد از تغییرات در فرم ، همون شی را برگردونم . اما همونطور که میبینین ، بعد از بستن فرم ، میگه اشاره گرِ این دو شی currentTranspControlBitmap.Equals(transCtrlBtmpEditorForm.CurrentAutoScaleDimensions) با هم برابر نیست.
چرا؟
با اونکه هم بصورت ref ارسال کردم . ref را هم برداشتم ، باز هم همون بود .
غیر از اینه که متغییرهای value و currentTranspControlBitmap و پروپرتی CurrentTransparentControlBitmap (در کلاس TransparentControlBitmapEditorForm) ، به یه شی اشاره میکنن؟
کلا میخوام اشاره گرِ currentTranspControlBitmap را بفرستم و همون اشاره گر را در متد EditValue برگردونم . چی کار باید کنم؟
با تشکر

کل کد رو اگه بخواین :


کد:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using CustomControl.Transparent;
using System.Security.Permissions;
using System.Drawing.Drawing2D;


namespace CustomControl.PropertiesEditor
{
    /// <summary>
    /// این کلاس ، برای ارسال و نمایشِ کلاس TransparentControlBitmapEditorForm و همچنین مقدارِ بازگشتیِ این کلاس ، در زمانِ طراحی (درون پنجره ی Properties مربوط به پروپرتی TransparentControlBitmap) هست .
    /// </summary>
    [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
    public class TransparentControlBitmapEditor : UITypeEditor
    {
        /// <summary>
        /// با مقدارِ بازگشتیِ این متد ، مشخص میکنیم که در پنجره ی Properties ، درون کادری که مربوط به مقداردهی پروپرتیِ مورد نظرمون هست (در اینجا پروپرتیِ  TransparentControlBitmap ، در سمتِ راستِ کادر ، چه نوع علامتی نشون داده بشه.
        /// </summary>
        /// <param name="context"></param>
        /// <returns>
        /// با مقدارِ بازگشتیِ این متد ، مشخص میکنیم که در پنجره ی Properties ، درون کادری که مربوط به مقداردهی پروپرتیِ مورد نظرمون هست (در اینجا پروپرتیِ  TransparentControlBitmap ، در سمتِ راستِ کادر ، چه نوع علامتی نشون داده بشه.
        /// </returns>
        public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
        {
            // گزینه ی UITypeEditorEditStyle.Modal مشخص میکنه که در پنجره ی Properties ، درون کادری که مربوط به مقداردهی پروپرتیِ مورد نظرمون هست (در اینجا پروپرتیِ  TransparentControlBitmap ، در سمتِ راستِ کادر ، علامتِ سه نقطه رو نشون بده.
            // برای نشون دادن فرم ، درون متد EditValue باید کدِ زیر را بنویسیم و متدِ edSvc.ShowDialog اش را اجرا کنیم.
            // IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));

            return UITypeEditorEditStyle.Modal;
        }

        /// <summary>
        /// زمانی این متد اجرا میشه که برنامه نویس درون پنجره ی Properties درون ویژال استودیو ، میخواد مقدار پروپرتی مورد نظر که در اینجا همون پروپرتی TransparentControlBitmap هست را تغییر بده . یعنی کنار اون دکمه ، کلیک کرد.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="provider"></param>
        /// <param name="value">
        /// مقدار جاریِ TransparentControlBitmap ، در این پارامتر ریخته میشه.
        /// </param>
        /// <returns>
        /// مقدارِ بازگشتیِ این تایع ، مقدارِ آخرِ پروپرتیِ مورد نظرمون (در اینجا پروپرتیِ TransparentControlBitmap را ست میکنه
        /// </returns>
        public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
        {
            // اگر مقدار value ، همون از نوع TransparentControlBitmap نبود ، ادامه نده.
            TransparentControlBitmap currentTranspControlBitmap = value as TransparentControlBitmap;
            if (currentTranspControlBitmap == null)
                return value;

            // برای نمایش فرم TransparentControlBitmapEditorForm مون ، لازم داریم provider را به نوعِ IWindowsFormsEditorService تبدیل کنیم.
            IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
            if (edSvc != null)
            {
                // اول شی ای از فرم TransparentControlBitmapEditorForm برای نمایش بسازه و مقدارِ جاریِ پروپرتی TransparentControl.TransparentControlBitmap را برایش در متد سازنده ی این کلاس توسط value ، ارسال کنه و بعد فرم را به نمایش بذاره تا برنامه نویس از صفحه ی فرم برای ویرایش مقادیر ، استفاده کنه.
                TransparentControlBitmapEditorForm transCtrlBtmpEditorForm = new TransparentControlBitmapEditorForm(ref currentTranspControlBitmap);
                edSvc.ShowDialog(transCtrlBtmpEditorForm);

                MessageBox.Show(currentTranspControlBitmap.Equals(transCtrlBtmpEditorForm.CurrentAutoScaleDimensions).ToString());
                // مقدار بازگشتی TransparentControlBitmap که بعد از اتمامِ صفحه ی طراحی ، برای پروپرتیِ TransparentControl.TransparentControlBitmap ست میشه.
                return currentTranspControlBitmap;
            }
            return value;
        }

        /// <summary>
        /// این متد ، درون کادرِ پروپرتی مورد نظر (پروپرتیِ TransparentControl.TransparentControlBitmap ) ، در سمت چپ اش ، آیکونی با این شکلی که درونِ این متد مینویسسم را رسم میکنه.
        /// </summary>
        /// <param name="e"></param>
        public override void PaintValue(PaintValueEventArgs e)
        {
            using (Pen pen = new Pen(Color.White, 1))
            {
                e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
                e.Graphics.DrawEllipse(pen, new Rectangle(new Point(2, 2), new Size(e.Bounds.Size.Width - 3, e.Bounds.Size.Height - 3)));
            }
        }

        /// <summary>
        /// مشخص میکنه که آیا شکل ای که در متدِ PaintValue تعیین کردیم ، درون کادرِ پروپرتی مورد نظر (پروپرتیِ TransparentControl.TransparentControlBitmap ) ، در سمت چپ اش ، رسم بشه یا نشه..
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public override bool GetPaintValueSupported(ITypeDescriptorContext context)
        {
            return true;
        }
    }


    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    internal class TransparentControlBitmapEditorForm : Form
    {
        private TransparentControlBitmap CurrentTransparentControlBitmap { get; set; }
        internal TransparentControlBitmapEditorForm(ref TransparentControlBitmap currentTranspControlBitmap)
        {
            this.CurrentTransparentControlBitmap = currentTranspControlBitmap;
        }

    }

}
transCtrlBtmpEditorForm.CurrentAutoScaleDimensions چه ربطی به transCtrlBtmpEditorForm.CurrentTransparentControlBitmap داره که private هم هست؟
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
transCtrlBtmpEditorForm.CurrentAutoScaleDimensions چه ربطی به transCtrlBtmpEditorForm.CurrentTransparentControlBitmap داره که private هم هست؟

transCtrlBtmpEditorForm.CurrentAutoScaleDimensions نوشتم . من فکر کردم CurrentTransparentControlBitmap رو نوشتم . هر دو تا Current داشتن اولش حواسم نبود . :green:
میگم خدایا چرا این جوری هه.
خیلی ممنون استاد.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلامی مجدد
استاد ، میگم پروپرتیِ TransparentControlBitmap ام (درون پنجره ی properties در ویژال استودیو) که در کادرِ جلویی اش ، آدرس کامل فضای نام به همراه نام کلاس را مینویسه (یعنی کد پست 1338 را گذاشتم ، این جوری مینویسه) ، میشه کاریش کرد که خودم هر چی دوست داشتم ، جلوی کادرِ پروپرتیِ TransparentControlBitmap بنویسم ؟ و همچنین کاری کنم که برنامه نویس هر چی دوست داشت بنویسه و من در این صورت ، چیزی که برنامه نویس نوشت را بتونم دریافت کنم؟ (فقط میخوام برنامه نویس بتونه عبارت null را بنویسه). یا اینکه وقتی روی پروپرتی ام کلیک راست کردم ، گزینه ای بنام null هم توی لیستِ کلیک راست اش اضافه بشه و برنامه نویس ، گزینه ی null را انتخاب کرد ، کار خاصی انجام بده؟
همچنین میشه کاری کرد که روی پروپرتی وقتی کلیک راست میکنیم ، گزینه ی ریست فعال باشه و کدی که من میخوام را اجرا کنه؟
اگه آره ، چجوری؟
خیلی ممنون
 
آخرین ویرایش:

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

بالا