سئوالات و مباحث WPF

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
آها . همین رو میخواستم بدونم . به نظرم چیزی که دنبالش میگشتم ، همین خطی که بولد کردم ، هست .
البته Model در MVVM ، با لایه ی "منطق تجاری" و لایه ی مربوط به "دیتابیس" در معماری 3 لایه ، فرقی نداره (بجز حالا فرضا بخشی از Model که در MVVM ممکنه در ViewModel بره) . درسته؟

اگه آره ، پس در MVVM نسبت به معماری 3 لایه ، صرفا بحث سازگار کردنِ بخشِ View یا منطق ارائه ، با Model هست . یعنی به عبارتی تفاوت MVVM (یا هر عبارت دیگه ای که میگید) با معماری 3 لایه ، اینه که در MVVM ، راحت تر و سریعتر لایه ی View را با لایه ی Model میشه هماهنگ کرد (معکوس اش ، نسبت به معماری 3 لایه ، فرقی نداره) .

چون شما در معماری 3 لایه ، در لایه ی منطق تجاری و لایه ی دیتابیس ، هر چیزی که داشته باشید ، عدل ، همه ی اینها را به عنوان لایه ی Model میتونید در یه پروژه ی دیگه در معماری MVVM منتقل کنید بدون هیچ تغییری در این لایه ها .

بنابراین فقط بحث هماهنگ کردن لایه ی View (و انتقالش و هماهنگ کردنش) با لایه ی Model هست که لایه ی ViewModel ، این هماهنگی را راحت تر و سریعتر میکنه .

درسته؟
تشکر استاد :rose:
ببخشید زیاد شد .

سلامی مجدد
خیلی ممنون استاد از جواب خوب تون .

نظرتون درباره ی این تیکه از صحبتم چیه؟
درسته؟
دقت کنید که این صحبتم ، در پازل مقایسه بین MVVM و معماری 3 لایه هست ها .

تشکر استاد :rose:
 

the_king

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

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
ViewModel قراره یک لایه سبکی ای باشه که این امکان رو طراحان نرم افزار بده تا به سادگی و در مدت زمان کم Model های مختلف رو با View های مختلف هماهنگ کنند. اما در معماری سه لایه Application خودش مسئولیت قابل توجهی داره، یک لایه بزرگ و پیچیده است، به سادگی نمیشه تغییرش داد. اگر تغییری در لایه Presentation یا Database رخ بده، دستکاری لایه سنگین Application لازم میشه.

سلامی مجدد
خیلی ممنون استاد .

استاد ، این ویژگی ای که نام بردین ، در جواب همون قسمتی از پستم که سئوال پرسیدم بود دیگه .
یعنی مزیتِ اضافی ترِ mvvm نسبت به معماری 3 لایه بود دیگه . درسته؟
یعنی همه ی مزایای mvvm نیست . درسته؟ فرضا مزیت mvvm نسبت به معماری یک لایه یا دو لایه نیست . درسته؟

در لینک های زیر :


و


و


مهمترین مزایای معماری 3 لایه را قابلیت همزمان نوشتن هر لایه توسط تیم توسعه بخاطر اجرای هر لایه در زیر ساخت مربوط به خودش هست ، نام میبرن .
مزایای دیگه ی این معماری را هم توسعه ی سریعتر ، بهبود Scale (که نمیدونم دقیقا این Scale چیه؟) و نگهداری راحت تر و اطمینان بهتر (که منظورشون از اطمینان را هم دقیق متوجه نشدم) هست .

همه ی این مزایا را برای معماری mvvm ، در سایت های مختلف هم بیان کرده بودن .
پس ، همه ی مزایای mvvm ، میشه همین ها (مزایای معماری 3 لایه) به اضافه ی چیزی که شما گفتین و نقل قول کردم در این پست ازتون . درسته؟
البته قابلیت تست راحت ترِ unit test را برای mvvm هم علاوه بر اونها آوردن .

تشکر استاد :rose:
 

the_king

مدیرکل انجمن
سلامی مجدد
خیلی ممنون استاد .

استاد ، این ویژگی ای که نام بردین ، در جواب همون قسمتی از پستم که سئوال پرسیدم بود دیگه .
یعنی مزیتِ اضافی ترِ mvvm نسبت به معماری 3 لایه بود دیگه . درسته؟
به چیزی که میگید، فکر کنید. پرتقال مزیتش نسبت به میوه چیه در حالی که خودش میوه است؟ اینجا مزیت که اصلا معنی نداره.
Window چه مزیتی نسبت به Control داره؟ مزیت اینجا معنی نداره. Window یک Control ئه که ویژگی های فلان رو داره. این ویژگی ها ممکنه با ویژگی های ListBox یا DataGridView یا موارد مشابه که همه شون هم مثل خودش Control هستند تشابه یا تفاوت هایی داشته باشند.
Control و Window همطراز نیستند که بخواهید با هم مقایسه شون کنید. معماری سه لایه و MVVM هم همینطور.
شما چیزی رو می توانید با چیز دیگری مقایسه کنید که همطراز باشند، تا حالا یک مقاله معتبر در سایتی دیده اید که یک چیزی رو با ذات خودش مقایسه کرده باشه، مزیت چیزی رو نسبت به ذاتش گفته باشه؟ در هر موضوع دلخواهی، کوکاکولا رو با نوشیدنی گازدار مقایسه کرده باشه، زن رو با انسان مقایسه کرده باشه، گنجشک رو با پرنده مقایسه کرده باشه، قرمز رو با رنگ مقایسه کرده باشه، بگردید ببینید همچین مقایسه ای در موضوعی هست؟ جستجو کنید از سال 2005 که صحبت MVVM شده تا حالا یک مقاله درست و حسابی، نمیگم صد تا، فقط یک مقاله در مورد مقایسه MVVM و معماری سه لایه هست که بگید منطق درستی داره و من هم دارم همونکار رو می کنم؟
یعنی همه ی مزایای mvvm نیست . درسته؟ فرضا مزیت mvvm نسبت به معماری یک لایه یا دو لایه نیست . درسته؟
مزایا و معایب برای مقایسه دو طرفی که همطراز هستند معنی داره. معماری یک لایه یا دو لایه همطراز MVVM نیستند که بتوانید با هم مقایسه شون کنید.
در لینک های زیر :


و


و


مهمترین مزایای معماری 3 لایه را قابلیت همزمان نوشتن هر لایه توسط تیم توسعه بخاطر اجرای هر لایه در زیر ساخت مربوط به خودش هست ، نام میبرن .
مزایای دیگه ی این معماری را هم توسعه ی سریعتر ، بهبود Scale (که نمیدونم دقیقا این Scale چیه؟) و نگهداری راحت تر و اطمینان بهتر (که منظورشون از اطمینان را هم دقیق متوجه نشدم) هست .
اگر اون مطالب رو با دقت بخونید می بینید که یا اصلا معماری سه لایه رو با چیزی مقایسه اش نکرده و صرفا فواید و معایب معماری سه لایه رو نوشته یا در یک مورد خاص با معماری دو لایه و سه لایه مقایسه اش کرده. از فواید الکل اینه که ضد عفونی کننده است، آیا من اینجا الکل رو با چیزی مقایسه کردم؟
توجه کنید و ببینید در مطالب چی با چی مقایسه شده، یا اصلا مقایسه ای در کار هست یا نه.
همه ی این مزایا را برای معماری mvvm ، در سایت های مختلف هم بیان کرده بودن .
پس ، همه ی مزایای mvvm ، میشه همین ها (مزایای معماری 3 لایه) به اضافه ی چیزی که شما گفتین و نقل قول کردم در این پست ازتون . درسته؟
البته قابلیت تست راحت ترِ unit test را برای mvvm هم علاوه بر اونها آوردن .
مزایای یک چیزی رو باید نسبت به چیز دیگری بسنجید، نسبت به چی مزیت داره؟ فرضا شما می خواهید بگید MVVM سرعت توسعه بیشتری داره، نسبت به کدوم معماری؟ یکجا میخونید که کاربری نوشته MVVM هزینه توسعه زیادی داره، نسبت به کدوم معماری هزینه بیشتری داره؟ نسبت به هر چی معماری در عالم بوده یا خواهد بود؟
 

SajjadKhati

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

استاد ، با این حرف زیر ام موافقید یا اگه نسبی هه ، تا چقدر موافقید؟ :

"تغییر در ماهیت User Interface ، نتیجه ی تغییر در Model هست" .

منظورم از تغییر ماهیت ، فرضا وقتی هست که در یک نسخه در UI ، یک combobox ای داشته باشیم (یا نداشته باشیم) اما در نسخه ی بعدی از همون UI ، اون کمبوباکس را حذف (یا اضافه) کنیم .
چون اول ، تصمیم گرفته میشه که یک قابلیتی (فرضا پروپرتی ای) را درون Model اضافه (یا حذف) کنیم و به نسبت اون تغییر هست که نیاز داریم تا ماهیت UI را تغییر بدیم (یا بسازیم) .

پس این طور نیست که وقتی ماهیت UI تغییر کنه ، به این دلیل باشه که Model مون تغییر میکنه . بلکه تغییر در Model مون بود که باعث تغییر در ماهیت UI مون شد .

از طرفی "تغییر در ظاهر (مثل تغییر در پوسته یا استایل یا template ئه) UI هم که اصلا باعث هیچ تغییری در Model نمیشه" .

نتیجه اینکه "اینکه با تغییر حتی UI ، لایه ی Model مون تغییر کنه ، موضوعیت نداره . بلکه موضوعیت و محوریت ، با تغییر Model هست . یعنی با تغییر Model هست که ممکنه ماهیت UI مون تغییر کنه" .

تشکر استاد .
 

the_king

مدیرکل انجمن
سلامی مجدد
خیلی ممنون استاد .

استاد ، با این حرف زیر ام موافقید یا اگه نسبی هه ، تا چقدر موافقید؟ :

"تغییر در ماهیت User Interface ، نتیجه ی تغییر در Model هست" .
اگر عبارت "تغییر در x نتیجه تغییر در y هست." درست باشه باید با تغییر در y ناگزیر و حتمی x تغییر کنه چون این نتیجه همچین عملی بوده.
حالا یک مثال رو فرض کنید که شما یک User Interface دارید که یک متن رو از کاربر میگیره و با صدای مرد یا زن میخونه. در نسخه قبلی Model بر اساس یک تکنیک ابتدایی پایگاه داده اصوات از قبل ضبط شده طراحی شده که متن ورودی رو به صوت تبدیل می کرده و حالا در نسخه جدید به یک هوش مصنوعی با یک سرویس آنلاین تغییر کرده که متن ورودی رو به صوت تبدیل می کنه. در Model یک تغییر اساسی رخ داده، معماری بانک اطلاعاتی و منطق تجاری کلا تغییر کرده. اما واسط کاربری همچنان همونه که بود، اصلا تغییر نکرده. همچنان متن رو از کاربر میگیره و صوت حاصل رو پخش میکنه.
منظورم از تغییر ماهیت ، فرضا وقتی هست که در یک نسخه در UI ، یک combobox ای داشته باشیم (یا نداشته باشیم) اما در نسخه ی بعدی از همون UI ، اون کمبوباکس را حذف (یا اضافه) کنیم .
حالا مثال قبلی رو با شرایط جدید تصور کنید. در نسخه قبلی پایگاه داده فقط دو نسخه صدای زن و مرد داشت و در نتیجه واسط کاربری در نسخه دوم همچنان فقط گزینه صدای زن و مرد داره. حالا در نسخه سوم واسط کاربری صدای بچه رو هم اضافه می کنند چون هوش مصنوعی Model این قابلیت رو داره که با مشخصات متفاوت صوت تولید کنه. Model در نسخه سوم نسبت به دوم هیچ تغییری نکرده، اما واسط کاربری تغییر می کنه. تغییر در واسط کاربری ربطی به تغییر در Model نداشت.
چون اول ، تصمیم گرفته میشه که یک قابلیتی (فرضا پروپرتی ای) را درون Model اضافه (یا حذف) کنیم و به نسبت اون تغییر هست که نیاز داریم تا ماهیت UI را تغییر بدیم (یا بسازیم) .

پس این طور نیست که وقتی ماهیت UI تغییر کنه ، به این دلیل باشه که Model مون تغییر میکنه . بلکه تغییر در Model مون بود که باعث تغییر در ماهیت UI مون شد .

از طرفی "تغییر در ظاهر (مثل تغییر در پوسته یا استایل یا template ئه) UI هم که اصلا باعث هیچ تغییری در Model نمیشه" .

نتیجه اینکه "اینکه با تغییر حتی UI ، لایه ی Model مون تغییر کنه ، موضوعیت نداره . بلکه موضوعیت و محوریت ، با تغییر Model هست . یعنی با تغییر Model هست که ممکنه ماهیت UI مون تغییر کنه" .
هر کدوم از لایه ها مستقل هستند، تغییر در داخل شون از دید خارج شون پنهان ئه، چیزی رو که به بیرون بروز میدن واسط شون ئه.
اینجا صحبت از واسط میان لایه ها است، نه واسط کاربری، نه واسط ارتباط با کاربر.
حالا یک لایه در محیط خارج با چی از اون لایه در ارتباط ئه؟ با اون واسط. پس اگر داخل لایه تغییری باشه اما واسط تغییر نکنه، بستر ارتباط تغییر نکرده و تغییری در خارج شون لازم نیست. اما حتی اگر در داخل تغییری نکنه، اما واسط ارتباط با خارج تغییری ناسازگار با قبلی داشته باشه، برای ارتباط با این واسط جدید نیاز به تغییرات در خارج هست. هر لایه ای که با این لایه با واسط جدید ارتباط ئه باید با اون تغییرات هماهنگ بشه.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
اگر عبارت "تغییر در x نتیجه تغییر در y هست." درست باشه باید با تغییر در y ناگزیر و حتمی x تغییر کنه چون این نتیجه همچین عملی بوده.
حالا یک مثال رو فرض کنید که شما یک User Interface دارید که یک متن رو از کاربر میگیره و با صدای مرد یا زن میخونه. در نسخه قبلی Model بر اساس یک تکنیک ابتدایی پایگاه داده اصوات از قبل ضبط شده طراحی شده که متن ورودی رو به صوت تبدیل می کرده و حالا در نسخه جدید به یک هوش مصنوعی با یک سرویس آنلاین تغییر کرده که متن ورودی رو به صوت تبدیل می کنه. در Model یک تغییر اساسی رخ داده، معماری بانک اطلاعاتی و منطق تجاری کلا تغییر کرده. اما واسط کاربری همچنان همونه که بود، اصلا تغییر نکرده. همچنان متن رو از کاربر میگیره و صوت حاصل رو پخش میکنه.

حالا مثال قبلی رو با شرایط جدید تصور کنید. در نسخه قبلی پایگاه داده فقط دو نسخه صدای زن و مرد داشت و در نتیجه واسط کاربری در نسخه دوم همچنان فقط گزینه صدای زن و مرد داره. حالا در نسخه سوم واسط کاربری صدای بچه رو هم اضافه می کنند چون هوش مصنوعی Model این قابلیت رو داره که با مشخصات متفاوت صوت تولید کنه. Model در نسخه سوم نسبت به دوم هیچ تغییری نکرده، اما واسط کاربری تغییر می کنه. تغییر در واسط کاربری ربطی به تغییر در Model نداشت.

هر کدوم از لایه ها مستقل هستند، تغییر در داخل شون از دید خارج شون پنهان ئه، چیزی رو که به بیرون بروز میدن واسط شون ئه.
اینجا صحبت از واسط میان لایه ها است، نه واسط کاربری، نه واسط ارتباط با کاربر.
حالا یک لایه در محیط خارج با چی از اون لایه در ارتباط ئه؟ با اون واسط. پس اگر داخل لایه تغییری باشه اما واسط تغییر نکنه، بستر ارتباط تغییر نکرده و تغییری در خارج شون لازم نیست. اما حتی اگر در داخل تغییری نکنه، اما واسط ارتباط با خارج تغییری ناسازگار با قبلی داشته باشه، برای ارتباط با این واسط جدید نیاز به تغییرات در خارج هست. هر لایه ای که با این لایه با واسط جدید ارتباط ئه باید با اون تغییرات هماهنگ بشه.

سلام
خیلی ممنون استاد .

پس جمله ی زیر چطور؟ :

"تغییر در View نیست که باعث تغییر Model میشه" .

و "در کل ، تغییر View ، موضوعیت و محوریت نداره" .

به این معنا که اگه View مون تغییر کنه ، یا اصلا نیازی نیست که Model مون تغییر کنه یا اینکه با تغییر Model هست که ممکنه باعث تغییر در ماهیت View بشه .

بخش دوم پاراگراف بالا ، یعنی این طور نیست که چون ماهیت View مون تغییر کرد ، پس حالا حتما باید یه تغییری در Model مون بدیم . بلکه محوریت تغییری که اگه باعث تغییر در ماهیت View بشه ، با Model هست و با View نیست (ممکنه حتی ماهیت View تغییر کنه بدون اینکه Model تغییر کرده باشه که گفتید و در اینجا هم گفتم . که در این پاراگراف ، این قسمتش منظورم نیست) .
 
آخرین ویرایش:

the_king

مدیرکل انجمن
سلام
خیلی ممنون استاد .

پس جمله ی زیر چطور؟ :

"تغییر در View نیست که باعث تغییر Model میشه" .
گزاره ها یا قواعد الزام آور دارند که هر مثال نقضی نادرست شون میکنه یا الزام آور نیستند که چون قطعیتی ندارند مطرح کردن شون بی فایده است.
وقتی لایه ها استقلال دارند دنبال رابطه قطعی و الزام آور گشتن بی مورد ئه.
مثلا یک View دارید که برای کاربران فارسی زبان طراحی شده، حالا View رو ویرایش می کنید تا بین المللی و چند زبانه بشه، در نتیجه Model رو هم ویرایش می کنید تا داده هایی با تفکیک زبانی ارائه بده. پس تغییر در View میتوانست منجر به نیاز تغییرات در Model بشه، و چون قطعیت نداره مطرح کردن بیفایده است. دنبال رابطه قطعی و قاعده الزام آوری میگردید که نیست.
و "در کل ، تغییر View ، موضوعیت و محوریت نداره" .
شما یک واسط کاربری در نظر بگیرید که برای کاربر عادی طراحی شده، وقتی تغییر کنه تا برای کاربر نابینا یا ناشنوا قابل استفاده بشه یک تغییر موضوعی و محوری است.
به این معنا که اگه View مون تغییر کنه ، یا اصلا نیازی نیست که Model مون تغییر کنه یا اینکه با تغییر Model هست که ممکنه باعث تغییر در ماهیت View بشه .
اینها هیچکدوم قطعی نیستند.
 

SajjadKhati

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

استاد ، در wpf در کد زیر :

C#:
        private void DisablerCheckBox_Unchecked(object sender, RoutedEventArgs e)
        {
            //if (this.WaitingLable != null)
            //    this.WaitingLable.Content = "لطفا چند ثانیه منتظر بمانید ...";

            this.EnableOperation();

            //if (this.WaitingLable != null)
            //    this.WaitingLable.Content = "";
        }

اون متد EnableOperation ، متد زمانبر (در حد چندین ثانیه) هست که باید در نخ اصلی انجام بشه .
اما قبل از اجرا ، میخوام مقدار محتوای لیبل WaitingLable را به همونی که نوشتم تغییر بدم .

اما به قول شما که اون دستور ، یه درخواست هست ، فوری عمل نمیکنه و بعد از اتمام اجرای متد EnableOperation عمل میکنه .
راهی هست که کاری کنم که قبل از اینکه اون متد اجرا بشه ، اون متن در لیبل ام نمایش داده بشه؟

تشکر :rose:
 

the_king

مدیرکل انجمن
سلام استاد
خیلی ممنون استاد .

استاد ، در wpf در کد زیر :

C#:
        private void DisablerCheckBox_Unchecked(object sender, RoutedEventArgs e)
        {
            //if (this.WaitingLable != null)
            //    this.WaitingLable.Content = "لطفا چند ثانیه منتظر بمانید ...";

            this.EnableOperation();

            //if (this.WaitingLable != null)
            //    this.WaitingLable.Content = "";
        }

اون متد EnableOperation ، متد زمانبر (در حد چندین ثانیه) هست که باید در نخ اصلی انجام بشه .
اما قبل از اجرا ، میخوام مقدار محتوای لیبل WaitingLable را به همونی که نوشتم تغییر بدم .

اما به قول شما که اون دستور ، یه درخواست هست ، فوری عمل نمیکنه و بعد از اتمام اجرای متد EnableOperation عمل میکنه .
راهی هست که کاری کنم که قبل از اینکه اون متد اجرا بشه ، اون متن در لیبل ام نمایش داده بشه؟

تشکر :rose:
اون کد هایی که در this.WaitingLable.Content تغییر ایجاد می کنند همونطور هستند که باید باشند، تغییری در اونها نخواهید داد.
اما فراخوانی اون EnableOperation باید با اولویت اجرایی کمتری باشه، باید به Dispatcher بگید که این EnableOperation رو در میان سایر روال ها با اولویتی اجرا کن که مزاحمتی برای عملیات های با اولویت بالاتر نداشته باشه، فرضا بروز رسانی نمایش WaitingLable رو در اولویت قرار بده و هر زمان بیکار شد EnableOperation رو اجرا کنه.
یک DispatcherFrame میسازید (using System.Windows.Threading) که تک فریم ئه و قرار نیست ادامه پیدا کنه
(frame.Continue = false) و در سرآغاز پشته فریم هایی که Dispatcher قراره اجرا کنه ارسالش می کنید (Dispatcher.PushFrame).
این فریم ابتدای پشته طبعا به سرعت نوبت اجرایش میرسه اما از Dispatcher میخواد که با اولویتی که مزاحم اجرای سایر روال ها نمیشه (DispatcherPriority.ContextIdle) اون EnableOperation رو اجرا کنه.
باید این روال خاتمه پیدا کنه تا فریم بعدی اجرا بشه، طبعا این EnableOperation مدتی سایر فریم های داخل پشته رو معطل می کنه و برای همین کد هایی که بعد از Dispatcher.PushFrame محتویات WaitingLable.Content رو پاک می کنند صبر خواهند کرد تا EnableOperation کارش تموم بشه.
C#:
using System.Windows.Threading;
.
.
.
        private void DisablerCheckBox_Unchecked(object sender, RoutedEventArgs e)
        {
            if (this.WaitingLable != null)
                this.WaitingLable.Content = "لطفا چند ثانیه منتظر بمانید ...";

            var frame = new DispatcherFrame();
            var op = Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.ContextIdle, new Action(delegate
            {
                this.EnableOperation();
            }));
            op.Completed += delegate (object ob, EventArgs ea)
            {
                frame.Continue = false;
            };
            Dispatcher.PushFrame(frame);

            if (this.WaitingLable != null)
                this.WaitingLable.Content = "";
        }
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
اون کد هایی که در this.WaitingLable.Content تغییر ایجاد می کنند همونطور هستند که باید باشند، تغییری در اونها نخواهید داد.
اما فراخوانی اون EnableOperation باید با اولویت اجرایی کمتری باشه، باید به Dispatcher بگید که این EnableOperation رو در میان سایر روال ها با اولویتی اجرا کن که مزاحمتی برای عملیات های با اولویت بالاتر نداشته باشه، فرضا بروز رسانی نمایش WaitingLable رو در اولویت قرار بده و هر زمان بیکار شد EnableOperation رو اجرا کنه.
یک DispatcherFrame میسازید (using System.Windows.Threading) که تک فریم ئه و قرار نیست ادامه پیدا کنه
(frame.Continue = false) و در سرآغاز پشته فریم هایی که Dispatcher قراره اجرا کنه ارسالش می کنید (Dispatcher.PushFrame).
این فریم ابتدای پشته طبعا به سرعت نوبت اجرایش میرسه اما از Dispatcher میخواد که با اولویتی که مزاحم اجرای سایر روال ها نمیشه (DispatcherPriority.ContextIdle) اون EnableOperation رو اجرا کنه.
باید این روال خاتمه پیدا کنه تا فریم بعدی اجرا بشه، طبعا این EnableOperation مدتی سایر فریم های داخل پشته رو معطل می کنه و برای همین کد هایی که بعد از Dispatcher.PushFrame محتویات WaitingLable.Content رو پاک می کنند صبر خواهند کرد تا EnableOperation کارش تموم بشه.
C#:
using System.Windows.Threading;
.
.
.
        private void DisablerCheckBox_Unchecked(object sender, RoutedEventArgs e)
        {
            if (this.WaitingLable != null)
                this.WaitingLable.Content = "لطفا چند ثانیه منتظر بمانید ...";

            var frame = new DispatcherFrame();
            var op = Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.ContextIdle, new Action(delegate
            {
                this.EnableOperation();
            }));
            op.Completed += delegate (object ob, EventArgs ea)
            {
                frame.Continue = false;
            };
            Dispatcher.PushFrame(frame);

            if (this.WaitingLable != null)
                this.WaitingLable.Content = "";
        }

سلامی مجدد
خیلی ممنون استاد .

برگرفته از کد شما ، با متد BeginInvoke ، فقط مقدار الویت اش را روی DispatcherPriority.Render قرار دادم که باعث شد بعد از اتمام رندر ، اون کد را اجرا کنه و درست شد :

C#:
        private void DisablerCheckBox_Unchecked(object sender, RoutedEventArgs e)
        {
            if (this.WaitingLable != null)
            {
                this.WaitingLable.Content = "لطفا چند ثانیه منتظر بمانید ...";
                //this.WaitingLable.IsEnabled = false;
            }


            this.Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action (delegate()
            {
                this.EnableOperation();

                if (this.WaitingLable != null)
                {
                    this.WaitingLable.Content = "";
                    //this.WaitingLable.IsEnabled = false;
                }
            }));

        }

هر چند این کدم ، خیلی اصولی ممکنه نباشه چون ابتدا ، تا اون لحظه ای که کنترل ، به متد BeginInvoke برسه ، این متد منتظر میمونه تا اول ، همه ی کدهای مربوط به رندر حتی در رویدادها و متدهای دیگه ای که اجا شده بودن و کلا در صف اجرا قرار داشته بودن ، ابتدا اونها اجرا و تمام بشن و بعدش این متد اجرا بشه . درسته؟
اما حالا جوابگوی کارم بود .

البته بعدش متوجه شدم که از async await هم برای این مشکلم میشه استفاده کرد .

----------

استاد ، در پروژه ی زیر (Windows Update Disabler که نسخه ی با ui اش را نوشتم) ، چرا وقتی روی دکمه ی "Click To Disable CheckBox" کلیک میکنیم ، با اونکه کد this.WaitingLable.IsEnabled = false; اجرا میشه اما لیبل مورد نظر غیر فعال نمیشه! چرا؟
عجیبه برام .

یه چیز دیگه اینکه وقتی روی آیکون برنامه که در system tray هست ، کلیک راست و گزینه ی "خروج" را کلیک میکنیم ، صفحه ی پرسش (messagebox) باز میشه اما اون popup و پنجره ای که گزینه ی "خروج" داشت ، تا زمانی که به messagebox پاسخ ندیم ، همچنان روی صفحه هست .
دلیل و نحوه ی رفع مشکل اش را میدونید چیه استاد؟
به همین قضیه ای که در پست قبلی مطرح کردم میتونه ربط داشته باشه؟

پی نوشت : با اجرای این برنامه ، زمان شروع برنامه ، سرویس های BITS و WinUpdate غیر فعال و stop داده میشن که با برداشتن همون تیک ، این سرویس ها ، فعال و شروع میشن .

تشکر استاد :rose:
 

پیوست ها

  • Windows Update Disabler.rar
    6.1 مگایابت · بازدیدها: 1
آخرین ویرایش:

the_king

مدیرکل انجمن
سلامی مجدد
خیلی ممنون استاد .

برگرفته از کد شما ، با متد BeginInvoke ، فقط مقدار الویت اش را روی DispatcherPriority.Render قرار دادم که باعث شد بعد از اتمام رندر ، اون کد را اجرا کنه و درست شد :

C#:
        private void DisablerCheckBox_Unchecked(object sender, RoutedEventArgs e)
        {
            if (this.WaitingLable != null)
            {
                this.WaitingLable.Content = "لطفا چند ثانیه منتظر بمانید ...";
                //this.WaitingLable.IsEnabled = false;
            }


            this.Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action (delegate()
            {
                this.EnableOperation();

                if (this.WaitingLable != null)
                {
                    this.WaitingLable.Content = "";
                    //this.WaitingLable.IsEnabled = false;
                }
            }));

        }

هر چند این کدم ، خیلی اصولی ممکنه نباشه چون ابتدا ، تا اون لحظه ای که کنترل ، به متد BeginInvoke برسه ، این متد منتظر میمونه تا اول ، همه ی کدهای مربوط به رندر حتی در رویدادها و متدهای دیگه ای که اجا شده بودن و کلا در صف اجرا قرار داشته بودن ، ابتدا اونها اجرا و تمام بشن و بعدش این متد اجرا بشه . درسته؟
اما حالا جوابگوی کارم بود .

البته بعدش متوجه شدم که از async await هم برای این مشکلم میشه استفاده کرد .

----------

استاد ، در پروژه ی زیر (Windows Update Disabler که نسخه ی با ui اش را نوشتم) ، چرا وقتی روی دکمه ی "Click To Disable CheckBox" کلیک میکنیم ، با اونکه کد this.WaitingLable.IsEnabled = false; اجرا میشه اما لیبل مورد نظر غیر فعال نمیشه! چرا؟
عجیبه برام .
غیر فعال شدنش چه فرقی داره که بخواهید متوجه تغییری بشوید؟
یه چیز دیگه اینکه وقتی روی آیکون برنامه که در system tray هست ، کلیک راست و گزینه ی "خروج" را کلیک میکنیم ، صفحه ی پرسش (messagebox) باز میشه اما اون popup و پنجره ای که گزینه ی "خروج" داشت ، تا زمانی که به messagebox پاسخ ندیم ، همچنان روی صفحه هست .
دلیل و نحوه ی رفع مشکل اش را میدونید چیه استاد؟
دلیلش شبیه مواردی است که قبلا بهش برخورد کردید، شما دارید روال رو در رخداد کلیک منو اجرا می کنید، اونجا کدی هست که منتظر میمونه تا کاربر تصمیم بگیره که میخواد از برنامه خارج بشه یا نه. هنوز از اون رخداد کلیک خارج نشده که بخواد پس از رخداد کلیک منو رو با روال عادی ببنده.
برای همین منو باز مونده و تا روال تموم نشه باز میمونه.
برای اینجور موارد می توانید از Command استفاده کنید که بستن منو رو منتظر روال داخل Command نمی کنه.
بستن پنجره رو فرضا با ApplicationCommands.Close انجام بدهیم :
XML:
                        <ContextMenu.CommandBindings>
                            <CommandBinding Command="ApplicationCommands.Close"
                                            Executed="ExecutedCloseCommand"
                                            CanExecute="CanExecuteCloseCommand" />
                        </ContextMenu.CommandBindings>
                        <MenuItem Header="نمایش پنجره" FontWeight="Bold" Click="ShowWindowTrayIcon_Click"/>
                        <MenuItem Header="درباره" Click="AboutTrayIcon_Click"/>
                        <MenuItem Header="خروج" Command="ApplicationCommands.Close"/>
اون CommandBinding لازمه، ApplicationCommands.Close به تنهایی کار نمی کنه، فرمان بستن پنجره باید توسط یک روال در پنجره اجرا بشه، اگه اون قسمت حذف بشه اجرا شدنی در کار نیست و گزینه "خروج" غیر فعال میشه.

C#:
        private void CanExecuteCloseCommand(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        private void ExecutedCloseCommand(object sender, ExecutedRoutedEventArgs e)
        {
            this.Close();
        }
به همین قضیه ای که در پست قبلی مطرح کردم میتونه ربط داشته باشه؟
بله. یک کدی هست که اومده اول رخداد کلیک رو بروز داده و بعد میخواد منو رو ببنده. شما داخل متد رخداد کلیک نگهش داشته اید، تا از اون متد در نیاد به کد های بعدی نمیرسه که منو رو ببنده.
 

SajjadKhati

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

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

میخوام بدونم چرا کد غیر فعال کردن لیبل ، کار نمیکنه؟

میخوام تا زمانی که متد مورد نظرم در نخ دیگه ای اجرا میشه ( چون از async await هم استفاده کردم) اون کنترلم را غیر فعال کنم که نمیدونم کدش چرا کدش عمل نمیکنه .

تشکر استاد
 

the_king

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

میخوام بدونم چرا کد غیر فعال کردن لیبل ، کار نمیکنه؟

میخوام تا زمانی که متد مورد نظرم در نخ دیگه ای اجرا میشه ( چون از async await هم استفاده کردم) اون کنترلم را غیر فعال کنم که نمیدونم کدش چرا کدش عمل نمیکنه .

تشکر استاد
سوالم رو متوجه نشدید؟ اگر عمل کنه چه اتفاقی می افته؟ وقتی Label غیر فعال شد چه تغییر ظاهری یا عملکردی داره که متوجه بشوید کار کرده؟
 

SajjadKhati

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

خیلی ممنون استاد
منظورتون اینه که وقتی لیبل غیر فعال شد ، تغییری در ظاهر لیبل اتفاق میافته که از روی ظاهرش ، متوجه ی غیر فعال شدنش بشیم؟

اگه منظورتون اینه ، بله .
Template ای که براش بکار برده شد ، برای حالت غیر فعال شدنش هم نوشته شد که تغییری بده .

البته این مهم نیست .
بالاخره وقتی غیر فعال بشه ، وقتی روش کلیک کنیم ، نباید به رویداد کلیک یا mouse over ، پاسخی بده دیگه .
اما وقتی کد غیر فعال سازیش را اجرا میکنم ، به این رویدادها همچنان پاسخ میده .

تشکر استاد .
 

the_king

مدیرکل انجمن
خیلی ممنون استاد
منظورتون اینه که وقتی لیبل غیر فعال شد ، تغییری در ظاهر لیبل اتفاق میافته که از روی ظاهرش ، متوجه ی غیر فعال شدنش بشیم؟

اگه منظورتون اینه ، بله .
Template ای که براش بکار برده شد ، برای حالت غیر فعال شدنش هم نوشته شد که تغییری بده .

البته این مهم نیست .
بالاخره وقتی غیر فعال بشه ، وقتی روش کلیک کنیم ، نباید به رویداد کلیک یا mouse over ، پاسخی بده دیگه .
اما وقتی کد غیر فعال سازیش را اجرا میکنم ، به این رویدادها همچنان پاسخ میده .

تشکر استاد .
کدوم متد وقتی روی این Label کلیک شد کاری انجام میده؟ کدوم Style وقتی ماوس روی این Label رفت ظاهرش رو تغییر میده؟
یا کدی که برای بررسی غیر فعال کردن WaitingLable بکار می برید محتویات دیگری داره که برای کلیک و Mouse Over و ... Template روال داره که قاعدتا شباهتی به آنچه آپلود کردید نداره یا توصیفی که می کنید برای DisablerCheckBox بوده و Label ئه WaitingLable رو با CheckBox ئه DisablerCheckBox اشتباه گرفته اید. وگرنه من هیچ موردی در پروژه تون نمی بینم که برای Label تون تفاوتی در Enable و Disable قائل شده باشه، چه ظاهر و چه عملکرد. نه کدی دارید که موقع Enable بودن WaitingLable با رخداد های ماوس متدی اجرا کنه و نه Style ای برایش اعمال کرده اید که با رخداد های ماوس تغییر ظاهری داشته باشه. یک Label ساده است با یک رنگ ثابت Foreground، چه فعال و چه غیر فعال. فعال بودنش با نبودنش فرقی نداره.
 

SajjadKhati

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

دلیلش شبیه مواردی است که قبلا بهش برخورد کردید، شما دارید روال رو در رخداد کلیک منو اجرا می کنید، اونجا کدی هست که منتظر میمونه تا کاربر تصمیم بگیره که میخواد از برنامه خارج بشه یا نه. هنوز از اون رخداد کلیک خارج نشده که بخواد پس از رخداد کلیک منو رو با روال عادی ببنده.
برای همین منو باز مونده و تا روال تموم نشه باز میمونه.
برای اینجور موارد می توانید از Command استفاده کنید که بستن منو رو منتظر روال داخل Command نمی کنه.
بستن پنجره رو فرضا با ApplicationCommands.Close انجام بدهیم :
XML:
                        <ContextMenu.CommandBindings>
                            <CommandBinding Command="ApplicationCommands.Close"
                                            Executed="ExecutedCloseCommand"
                                            CanExecute="CanExecuteCloseCommand" />
                        </ContextMenu.CommandBindings>
                        <MenuItem Header="نمایش پنجره" FontWeight="Bold" Click="ShowWindowTrayIcon_Click"/>
                        <MenuItem Header="درباره" Click="AboutTrayIcon_Click"/>
                        <MenuItem Header="خروج" Command="ApplicationCommands.Close"/>
اون CommandBinding لازمه، ApplicationCommands.Close به تنهایی کار نمی کنه، فرمان بستن پنجره باید توسط یک روال در پنجره اجرا بشه، اگه اون قسمت حذف بشه اجرا شدنی در کار نیست و گزینه "خروج" غیر فعال میشه.

C#:
        private void CanExecuteCloseCommand(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        private void ExecutedCloseCommand(object sender, ExecutedRoutedEventArgs e)
        {
            this.Close();
        }

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

سلامی مجدد
خیلی ممنون استاد .

این کد command را گذاشتم . برنامه بسته میشه اما مثل حالت قبل ، وقتی روی منوی "خروج" کلیک میکنم ، تا جوابی به پرسش خروج ندم ، (رندر و نمایشِ) اون منو ، همچنان نشون میده .

async await را هم تست کردم ، منتظر خروجی و جواب پرسش نمیمونه.

کدوم متد وقتی روی این Label کلیک شد کاری انجام میده؟ کدوم Style وقتی ماوس روی این Label رفت ظاهرش رو تغییر میده؟
یا کدی که برای بررسی غیر فعال کردن WaitingLable بکار می برید محتویات دیگری داره که برای کلیک و Mouse Over و ... Template روال داره که قاعدتا شباهتی به آنچه آپلود کردید نداره یا توصیفی که می کنید برای DisablerCheckBox بوده و Label ئه WaitingLable رو با CheckBox ئه DisablerCheckBox اشتباه گرفته اید. وگرنه من هیچ موردی در پروژه تون نمی بینم که برای Label تون تفاوتی در Enable و Disable قائل شده باشه، چه ظاهر و چه عملکرد. نه کدی دارید که موقع Enable بودن WaitingLable با رخداد های ماوس متدی اجرا کنه و نه Style ای برایش اعمال کرده اید که با رخداد های ماوس تغییر ظاهری داشته باشه. یک Label ساده است با یک رنگ ثابت Foreground، چه فعال و چه غیر فعال. فعال بودنش با نبودنش فرقی نداره.

واقعا ببخشید .
نمیدونم چرا گاها این اشتباهای فاحش را میکنم .
نام کنترل را اشتباه در نظر گرفتم و مد نظرم ، کنترل DisablerCheckBox بوده که اشتباها کنترل WaitingLabel را نوشتم اما فکر میکردم که DisablerCheckBox را نوشته بودم .

تشکر استاد .
 

the_king

مدیرکل انجمن
سلامی مجدد
خیلی ممنون استاد .

این کد command را گذاشتم . برنامه بسته میشه اما مثل حالت قبل ، وقتی روی منوی "خروج" کلیک میکنم ، تا جوابی به پرسش خروج ندم ، (رندر و نمایشِ) اون منو ، همچنان نشون میده .

async await را هم تست کردم ، منتظر خروجی و جواب پرسش نمیمونه.
نمیدونم دلیل کار نکردن کدی که نوشته بودم چیه. می توانید با تایمر یا وقفه در نخ جانبی به نخ اصلی مقداری مهلت بدهید.
C#:
            Task.Delay(1000).ContinueWith(t => Dispatcher.Invoke(new Action(() => this.Close())));
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
نمیدونم دلیل کار نکردن کدی که نوشته بودم چیه. می توانید با تایمر یا وقفه در نخ جانبی به نخ اصلی مقداری مهلت بدهید.
C#:
            Task.Delay(1000).ContinueWith(t => Dispatcher.Invoke(new Action(() => this.Close())));

سلامی مجدد
خیلی ممنون استاد .
بله .
علاوه بر تایمر ، همونطور که توضیح دادید ، نخ جدیدی (با thread یا task و ...) که توش مقداری (فرضا 300 میلی ثانیه یا کمتر و بیشتر) ، این نخ را منتظر بذاریم و بعد از انتظار ، کد بستن پنجره ی ویندوز را در نخ اصلی (توسط متد Dispatcher.Invoke) بنویسیم هم مثل همین کار میکنه .

استاد ، لینک زیر انگار میگه که با اونکه Task ها ، Disposable هستند ، اما نیاز به فراخونی این متد نیست . هر چند توضیح داد اما من دو تا پاراگراف اول رو خوندم اما دلیل واقعیش را متوجه نشدم :


تشکر استاد .
 

the_king

مدیرکل انجمن
استاد ، لینک زیر انگار میگه که با اونکه Task ها ، Disposable هستند ، اما نیاز به فراخونی این متد نیست . هر چند توضیح داد اما من دو تا پاراگراف اول رو خوندم اما دلیل واقعیش را متوجه نشدم :

نمیگه هیچوقت نیازی نیست که اینکار رو بکنید، میگه معمولا لازم نیست که اینکار رو بکنید. منطقی که برای حرف اش داره اینه که معمولا شما از Task به صورتی استفاده می کنید که اهمیتی نداره که Dispose شدن منابع مدیریت نشده اش با تاخیر انجام بشه. اشیاء زیادی هستند که مدیریت Dispose شدن شون برای برنامه نویس راحت نیست و برای همین موقع ایجاد شون جایی ثبت می شوند و در پایان اجرای برنامه یا در شرایط مشخصی که دیگه قابل استفاده نیستند، Dispose می شوند، حتی اگر زودتر خودتون اینکار رو نکنید. یعنی Net. برای جلوگیری از نشت منابع بعضی اشیاء کد هایی داره که اگر خودتون زودتر Dispose شون نکنید که معمولا نمی کنید، بالاخره زمانی اون Dispose رو انجام خواهد داد. مثال اش اینه که شما نگران Dispose شدن کنترل های روی فرم نیستید، چه کنترل هایی که Designer ایجاد کرده و چه کنترل هایی که بعدا با کد روی فرم اضافه می کنید، خود فرم مدیریت شون می کنه.
حالا مهمه که اون اشیاء زودتر Dispose بشوند و فرضا منتظر پایان اجرای برنامه نشویم؟ معمولا نه، مهم نیست.
Task.Dispose Method
The Task class implements the IDisposable interface because internally it uses resources that also implement IDisposable. However, particularly if your app targets the .NET Framework 4.5 or later, there is no need to call Dispose unless performance or scalability testing indicates that, based on your usage patterns, your app's performance would be improved by disposing of tasks. For more information, see Do I need to dispose of Tasks? in the Parallel Programming with .NET blog.​
 

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

بالا