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

SajjadKhati

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

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


بله.

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

درباره ی مزایای MVVM .
به نظرم ، مهمترین و کلیدی ترین کلمه ، همون "محدودیت های کمتری" بود که گفتین .
یعنی صرفِ پیاده سازیِ MVVM ، باعث نمیشه که (نسبت به پروژه ی غیرِ MVVM) ، با تغییر دادنِ یک لایه ، بقیه ی لایه ها نیاز به تغییر نداشته باشن و ... . و در کل باعث نمیشه که کلا مشکلی که وجود داشت ، اصلا بوجود نیاد .
بلکه پیاده سازیِ MVVM باعث میشه که نیاز به این تغییرات و مشکلات ، به کمترین میزان خودش برسه و همچنین اینکه روابط لایه ها ، منسجم تر بشن .
درست میگم؟

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

the_king

مدیرکل انجمن
سلامی مجدد
خیلی ممنون استاد .
استاد پروژه ی زیر را لطفا ببینید .

اول روی دکمه ای که محتواش نوشته "Mouse Enter Change Student Member Value" برید (دکمه ی بالا سمت راست) :

- حالا اگه روی کنترل ListView موس را روی آیتم های مختلف ببرید ، چون در رویداد ListViewItem_MouseEnter ، با متد ICollectionView.MoveCurrentTo ، مقدارِ پروپرتیِ CurrentItem ئه CollectionView ی پیش فرض را تغییر دادم ، خوب مشخص هست که چون پروپرتیِ Header ئه شیِ سوم از GridViewColumn (در کنترل ListView) ، به CurrentItem متصل و Binding شد ، مقدارش به همونی که در اون متد داده بودیم ، تغییر میکنه .

- اما وقتی که اون کد ، یعنی متد ICollectionView.MoveCurrentTo در رویداد ListViewItem_MouseEnter را کامنت (یا حذف) کنید و همچنین اگه روی آیتم های ListView ، کلیک کنید ، این اتفاق نمیافته و CurrentItem تغییر نمیکنه . که شاید طبیعی به نظر برسه .

اما من جایی خونده بودم (اگه درست یادم بیاد) که کاربر نهایی با کلیک و انتخاب آیتم ها (در کنترل هایی که به یه کالکشن ای Binding شدن) ، باعث میشه تا پروپرتیِ CurrentItem ئه اون CollectionView بصورت اتوماتیک به همون آیتم ، تغییر مقدار بده .
حالا نمیدونم برداشت من از اون مطلب اشتباه بوده یا جریان چیز دیگه ای هست؟
تشکر استاد .
من یک هفته دسترسی به لپ تاپ ندارم، اگر در سوالی نیازی بهش باشه باید صبر کنید که برگردم ایران. انتخاب گزینه به شرط IsSynchronizedWithCurrentItem منجر به اون بروز رسانی میشه، اما انتخاب گزینه، نه الزاما رخدادی مثل MouseEnter.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
من یک هفته دسترسی به لپ تاپ ندارم، اگر در سوالی نیازی بهش باشه باید صبر کنید که برگردم ایران. انتخاب گزینه به شرط IsSynchronizedWithCurrentItem منجر به اون بروز رسانی میشه، اما انتخاب گزینه، نه الزاما رخدادی مثل MouseEnter.

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

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

نه. شما استخراج داده از View تون رو سخت یا آسون باید در همون View انجام بدهید و فقط داده استخراج شده رو به ViewModel ارسال کنید.
المنت های View که نباید قاطی پردازش Model بشوند. هر ارجاعی به المنت ها رو صرفا باید در View نگهدارید.

در بهترین حالت هیچی، میذاریدش کنار، یعنی کل معماری فعلی رو نادیده می گیرید، و از نو با معلومات به روز شده تون طراحی اش می کنید و در همه بخش ها اون تفکیک View و Model و ViewModel رو در نظر می گیرید.

خیلی ممنون استاد .
میگم استاد ، این کلاس InteropWithUI که در پست 724 گفته بودم ، با توجه به نکاتی که گفته بودین ، الان فکر میکنم که جزء لایه ی View قرار میگیره (نه جزء لایه ی Model که قبلا میگفتم) .

اعضا و متدهاش ، یا پارامتر از نوع کنترلی را میگیرن ، یا الگوریتمی دارن که به یا کنترل و یا کلا کارهای بصری و گرافیکی و اینها مربوط میشه و یا به Application که جزء لایه ی View هست ، مربوط میشه .



در MVVM ، اگه فرضا این کلاسِ InteropWithUI ، جزء لایه ی View (یا هر لایه ی دیگه ای) هست ، لزومی نداره که این کلاس را با کلاسِ MainWindow (که به عنوان لایه ی View مون در اینجا هست) ، ترکیب کنیم .

در MVVM ، صرفا ارتباط مهم هست . یعنی InteropWithUI میتونه کلاس مجزا باشه اما چون جزء View مون محسوب میشه ، پس برای ارتباط برقرار کردن و مقداردهی و فراخونیِ اعضای این کلاسِ InteropWithUI ، باید از طریق کلاس View مون که همون کلاس MainWindow در اینجا هست ، این کار را انجام بدیم .

یعنی برای ارتباط برقرار کردن با InteropWithUI ، از لایه ی ViewModel یا Model مون این کار را انجام ندیم .
درست گفتم؟

همچنین استاد این پست و پست قبلی (پست 781) را هر وقت فرصت داشتین ، بی زحمت جواب بدین (مهم نیست چه وقتی . هر وقت فرصت داشتین) .
تشکر استاد .
 

SajjadKhati

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

متوجه ی منظورم شدید؟
به نظرم فرق خاصی ندارن . دارن؟
تشکر استاد .
 

the_king

مدیرکل انجمن
سلامی مجدد
استاد ، میگم اگه در لایه ی Model مون ، 2 تا کلاس داشتیم که برای هر دوشون نیاز باشه که با ViewModel در تماس باشن (فرضا یعنی در ViewModel مون نیاز باشه که از هر دو کلاسی که در Model مون هست ، شی بسازیم) ، در این صورت فرقی داره که برای هر کدوم از اون دو کلاس در Model مون ، یک کلاسِ ViewModel (بصورت اختصاصی بسازیم) یا اینکه فقط یک کلاس از ViewModel ایجاد کنیم و در اون ، دو شی از اون دو کلاسی که درون Model مون هستن ، ایجاد کنیم؟

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


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

SajjadKhati

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


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

سلامی مجدد استاد .
آها .
پس design pattern یا الگوی طراحی ، چیزی هست که فرضا مشخص میکنه در اپلیکیشنی خاص (اپلیکیشن مون) ، چه مقدار کلاس بسازیم . کلاس ها از هم ارث بری کنن بهتره یا از اینترفیس و کلاس های abstract استفاده کنیم . این ها چند تا (کلاس و اینترفیس و ...) باشن ، خوبه .
الگوی طراحی ، از این دست چیزها را مشخص میکنه .
درسته؟

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

اما خیلی کلی گفتین .
الان مثلا توی اون لینکی که دادین ، چه نوع الگوی طراحی ای باشه ، مناسب هست که درون یک کلاس از ViewModel مون ، از هر دو کلاسی که در Model مون وجود داره ، شی بسازیم و استفاده کنیم؟
و در چه نوع الگوی طراحی ، مناسب هست که دو تا کلاسِ ViewModel ، برای ارتباط با دو کلاسی که در Model مون وجود داره ، ایجاد کنیم؟

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

من یه کلاس بنام VssBackup دارم که منطق تجاری برای کارهای بکاپ گیری هست .
یه کلاس ExtentionMethod دارم که متدهایی هست که بصورت Extention میخوام به کلاسِ System.IO.DriveInfo متصل کنم .
معمولا این دو کلاس (VssBackup و ExtentionMethod) از هم جدا هستن . یعنی درون کلاس VssBackup ، از ExtentionMethod استفاده نمیشه (حداقل تا حالا که نشده) . ولی هر دوشون با View لازمه که (توسط ViewModel) رابطه داشته باشن .
البته شاید بعدا نیاز باشه در کلاس VssBackup ، از ExtentionMethod هم استفاده بشه . فعلا دقیق مشخص نیست .

برای همچین طراحی ای (که نمیدونم از کدوم الگوی طراحی استفاده میکنه چون الگوهای طراحی را نمیشناسم) ، به نظرتون در یک کلاس از ViewModel از هر دوی این کلاس ها شی بسازم بهتره یا دو تا ViewModel ئه مجزا براشون در نظر بگیرم؟

هر زمانی که وقت داشتین ، جواب بدین ، ممنون میشم .
تشکر استاد .
 

the_king

مدیرکل انجمن
سلامی مجدد استاد .
آها .
پس design pattern یا الگوی طراحی ، چیزی هست که فرضا مشخص میکنه در اپلیکیشنی خاص (اپلیکیشن مون) ، چه مقدار کلاس بسازیم . کلاس ها از هم ارث بری کنن بهتره یا از اینترفیس و کلاس های abstract استفاده کنیم . این ها چند تا (کلاس و اینترفیس و ...) باشن ، خوبه .
الگوی طراحی ، از این دست چیزها را مشخص میکنه .
درسته؟
بله. اما افراط و تفریط اش رو الگو ها مشخص نمی کنند، شما می کنید. ممکنه دو نفر از یک الگو استفاده کنند اما یکی شون در حد متعادل و دیگری افراطی. برای همین تعداد کلاسهاشون الزاما یک اندازه نمیشه.
اما خیلی کلی گفتین .
الان مثلا توی اون لینکی که دادین ، چه نوع الگوی طراحی ای باشه ، مناسب هست که درون یک کلاس از ViewModel مون ، از هر دو کلاسی که در Model مون وجود داره ، شی بسازیم و استفاده کنیم؟
و در چه نوع الگوی طراحی ، مناسب هست که دو تا کلاسِ ViewModel ، برای ارتباط با دو کلاسی که در Model مون وجود داره ، ایجاد کنیم؟
کلی ئه، چون سوال تون هم کلی ئه. توضیحی که می دهید یک حالت کلی ئه، ارتباط با دو تا کلاس که جزئیات انتخاب الگو نیست.
من یه کلاس بنام VssBackup دارم که منطق تجاری برای کارهای بکاپ گیری هست .
یه کلاس ExtentionMethod دارم که متدهایی هست که بصورت Extention میخوام به کلاسِ System.IO.DriveInfo متصل کنم .
معمولا این دو کلاس (VssBackup و ExtentionMethod) از هم جدا هستن . یعنی درون کلاس VssBackup ، از ExtentionMethod استفاده نمیشه (حداقل تا حالا که نشده) . ولی هر دوشون با View لازمه که (توسط ViewModel) رابطه داشته باشن .
البته شاید بعدا نیاز باشه در کلاس VssBackup ، از ExtentionMethod هم استفاده بشه . فعلا دقیق مشخص نیست .

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

SajjadKhati

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

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

منظورتون از روابط ، اعضا(ی کلاس) هستن؟
بازم کلی شد :)
یعنی مثلا چه مواردی به هم ربط داشته باشن باعث میشه که در یک کلاس از ViewModel ، از هر دو کلاس در Model مون شی درست کنیم؟ و همچنین در مورد دیگه ، دو کلاسِ مجزای ViewModel ایجاد کنیم؟

کلا یه کم با جزئیات بیشتری توضیح بدین ، ممنون میشم .
تشکر استاد .
 

the_king

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

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

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

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

SajjadKhati

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

من 2 تا کلاس به عنوان Model دارم به نام های VssBackup و ExtentionMethodForDriveInfo .
2 تا کلاس به عنوان ViewModel ساختم به نام های VssBackupViewModel و ExtentionMethodViewModel .
فعلا هم 2 تا ویندوز دارم به نام های MainWindow و SettingWindow (که هر دو از کلاس Window ارث بری میکنن) .

حالا توی این دو تا ویندوزِ MainWindow و SettingWindow ، برای اینکه با ViewModel ها در ارتباط باشم ، میخوام در هر کدوم از این ویندوزها ، پروپرتی ای از نوع VssBackupViewModel و ExtentionMethodViewModel بسازم .

حالا میگم اگه بعدا چند تا ویندوز دیگه هم اضافه کنم (فرضا کلا 5 تا ویندوز بسازم) ، سخت میشه که در هر کدوم از کلاس های این ویندوزها ، پروپرتی های از نوعِ VssBackupViewModel و ExtentionMethodViewModel بسازم . یعنی در 5 تا ویندوز ، 10 تا پروپرتیِ مجزا باید بسازم .

به نظرتون بهترین کار برای اینکه این پروپرتی ها را ، فقط یه بار در هر یک از این ویندوزها تعریف کنم و بعد در این ویندوزها فراخونی و استفاده کنم ، اینه که برای نوع Window ، یه extension method بسازم و در بقیه استفاده کنم؟
یا اینکه ساخت extension method را برای این کار پیشنهاد نمیکنید؟
یا اینکه روش دیگه ی بهتری وجود داره؟

استاد ، میگم اگه وقت کردین هم پست های 783 و 781 را هم جواب بدین ، ممنون میشم .
تشکر استاد .
 

SajjadKhati

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

من 2 تا کلاس به عنوان Model دارم به نام های VssBackup و ExtentionMethodForDriveInfo .
2 تا کلاس به عنوان ViewModel ساختم به نام های VssBackupViewModel و ExtentionMethodViewModel .
فعلا هم 2 تا ویندوز دارم به نام های MainWindow و SettingWindow (که هر دو از کلاس Window ارث بری میکنن) .

حالا توی این دو تا ویندوزِ MainWindow و SettingWindow ، برای اینکه با ViewModel ها در ارتباط باشم ، میخوام در هر کدوم از این ویندوزها ، پروپرتی ای از نوع VssBackupViewModel و ExtentionMethodViewModel بسازم .

حالا میگم اگه بعدا چند تا ویندوز دیگه هم اضافه کنم (فرضا کلا 5 تا ویندوز بسازم) ، سخت میشه که در هر کدوم از کلاس های این ویندوزها ، پروپرتی های از نوعِ VssBackupViewModel و ExtentionMethodViewModel بسازم . یعنی در 5 تا ویندوز ، 10 تا پروپرتیِ مجزا باید بسازم .

به نظرتون بهترین کار برای اینکه این پروپرتی ها را ، فقط یه بار در هر یک از این ویندوزها تعریف کنم و بعد در این ویندوزها فراخونی و استفاده کنم ، اینه که برای نوع Window ، یه extension method بسازم و در بقیه استفاده کنم؟
یا اینکه ساخت extension method را برای این کار پیشنهاد نمیکنید؟
یا اینکه روش دیگه ی بهتری وجود داره؟

استاد ، میگم اگه وقت کردین هم پست های 783 و 781 را هم جواب بدین ، ممنون میشم .
تشکر استاد .

راستی ، اون که extension method (متد) هست .
من نیاز به پروپرتی دارم .

کاری نمیشه کرد جز اینکه در همه ی ویندوزها ، دونه دونه ی اون پروپرتی ها را تعریف کنم؟
یا راه دیگه ای هم هست؟

مثلا یه کلاسی تعریف کنم که از Window ارث بری کنه (فرضا بنام کلاس A) . بعد ، MainWindow و SettingWindow ، از اون کلاس A ارث بری کنن .
اما این راهکار چندان جالبی صرفا برای اضافه کردنِ 2 یا چند تا پروپرتی نیست . هست؟
کلا شما چی پیشنهاد میدید؟

تشکر استاد .
 
آخرین ویرایش:

the_king

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

من 2 تا کلاس به عنوان Model دارم به نام های VssBackup و ExtentionMethodForDriveInfo .
2 تا کلاس به عنوان ViewModel ساختم به نام های VssBackupViewModel و ExtentionMethodViewModel .
فعلا هم 2 تا ویندوز دارم به نام های MainWindow و SettingWindow (که هر دو از کلاس Window ارث بری میکنن) .

حالا توی این دو تا ویندوزِ MainWindow و SettingWindow ، برای اینکه با ViewModel ها در ارتباط باشم ، میخوام در هر کدوم از این ویندوزها ، پروپرتی ای از نوع VssBackupViewModel و ExtentionMethodViewModel بسازم .

حالا میگم اگه بعدا چند تا ویندوز دیگه هم اضافه کنم (فرضا کلا 5 تا ویندوز بسازم) ، سخت میشه که در هر کدوم از کلاس های این ویندوزها ، پروپرتی های از نوعِ VssBackupViewModel و ExtentionMethodViewModel بسازم . یعنی در 5 تا ویندوز ، 10 تا پروپرتیِ مجزا باید بسازم .
سخت نمیشه، دو تا پروپرتی به ازای هر پنجره چه سختی ای داره؟ عملیات زمانبر یا پیچیده ای که نیست، یک Copy/Paste ساده است.
به نظرتون بهترین کار برای اینکه این پروپرتی ها را ، فقط یه بار در هر یک از این ویندوزها تعریف کنم و بعد در این ویندوزها فراخونی و استفاده کنم ، اینه که برای نوع Window ، یه extension method بسازم و در بقیه استفاده کنم؟
احتمالا Extension Method و Attached Property مناسب کار شما نیست، چون اینها به تنهایی کار نمی کنند، یک روالی در اون پنجره ها باید باشه که بر اساس اینها عمل کنه.
یا اینکه ساخت extension method را برای این کار پیشنهاد نمیکنید؟
نمیدونم دارید چیکار می کنید ولی احتمالا مناسبش نیست.
یا اینکه روش دیگه ی بهتری وجود داره؟
بخاطر دو تا مشخصه نیازی به اینکار نیست، اما اگر تعداد پنجره ها با اون ویژگی زیاد ئه، قاعدتا باید یک وراثت از کلاس پنجره داشته باشید.
استاد ، میگم اگه وقت کردین هم پست های 783 و 781 را هم جواب بدین ، ممنون میشم .
پاسخی برای اون پست های 781 و 783 ندارم، شما یک حکم صادر کرده اید که "پیاده سازیِ MVVM باعث میشه که نیاز به این تغییرات و مشکلات ، به کمترین میزان خودش برسه"، نه ارجاعی به یک تحقیقات مشخصی کرده اید، نه آماری ارائه کرده اید که خودتون فلان تعداد پروژه رو مطالعه کرده اید که این نتیجه گیری از تحلیل آمارشون ارائه شده، نه فاکتور و معیاری برای اون کمترین میزان ارائه کرده اید که مشخص بشه کمترین چقدر ئه؟ معیارش چیه؟ چقدر کم میشه؟ اونوقت من باید بگم این حکم درسته یا نه؟ اگه من بگم درسته، حکم بی پایه و اساسی که هیچ آمار و مطالعه ای پشتش نیست درست میشه؟
یک حکم هم صادر کرده اید که "در MVVM ، صرفا ارتباط مهم هست"، نمیدونم مبنا اش چیه، جایی همچین چیزی نوشته شده؟ شما باید بگید منبع اش کجاست و چه توضیحی داره، من اطلاعی از این قضیه ندارم.
راستی ، اون که extension method (متد) هست .
من نیاز به پروپرتی دارم .

کاری نمیشه کرد جز اینکه در همه ی ویندوزها ، دونه دونه ی اون پروپرتی ها را تعریف کنم؟
یا راه دیگه ای هم هست؟
شما چه مشخصه رو در کلاس وارث پنجره تعریف کنید و چه از مشخصه های الحاقی استفاده کنید نهایتا روال هایی دارید که از اون مشخصه ها استفاده می کنند، برای همین صرفا وجود مشخصه کافی نیست.
مثلا یه کلاسی تعریف کنم که از Window ارث بری کنه (فرضا بنام کلاس A) . بعد ، MainWindow و SettingWindow ، از اون کلاس A ارث بری کنن .
اما این راهکار چندان جالبی صرفا برای اضافه کردنِ 2 یا چند تا پروپرتی نیست . هست؟
اگر یک ویژگی خاص به اون پنجره اضافه میشه که اون مشخصه ها برای اون ویژگی است، تعریف کلاس اختصاصی قطعا مناسب ئه، اما اگر صرفا برای فرار از تعریف مجدد دو تا مشخصه در چند پنجره اینکار رو می کنید دلیلی برای این گریز نمی بینم.
 

SajjadKhati

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

یعنی فرضا یه enum (یا حتی کلاس) ای را در Model مون تعریف کردیم ، حالا طبق محاسباتی که در متدی که در کلاسی که در Model مشخص کردیم ، اون متد ، مقداری از اون enum را برمیگردونه که این مقدار را در لایه ی View مون نیاز داریم (فرضا مقدارِ enum ئه مورد نظر را که بدست اومد را میخوایم در متغییرِ محلی در لایه ی View استفاده کنیم) .

این کار را میشه انجام داد و مشکلی نداره دیگه؟
یعنی میشه متغییر محلی ای (یا پروپرتی و ...) را در View ، از نوعِ enum (یا کلاس و ...) ای که در Model تعریف کرده بودیم ، بگیریم ؟
چون من نیاز قطعی دارم که در View ام ، حداقل نوعِ اون enum را در متغییرم ذخیره کنم .

الان آیا شما میگید که این کار شدنی هست اما نباید به اعضای اون enum دسترسی داشته باشم؟
بجاش اگه برای محاسباتی که نیاز باشه به اعضای اون enum بخوام دسترسی داشته باشم ، باید شیِ enum را که در متغییری ذخیره کرده بودم ، بفرستم به Model ، تا اونجا محاسبه کنم و نهایتا مقدارِ آخری که ربطی به اعضای Model نداره (داده) را برگردونم؟

بذارید واضح تر بگم .
کدم اینه :

C#:
        public void FillComboBoxByDriveInfos(ComboBox comboBox)
        {
            DriveInfo[] driveInfos = ExtensionMethodViewModel.GetFixedNtfsDrives();
            if (driveInfos == null || driveInfos.Length < 1)
                return;
            foreach (DriveInfo driveInfo in driveInfos)
            {
                // فقط اولین کاراکتر که نام درایو (بدون کاراکتر اسلش) هست را برمیگردونه
                string driveName = driveInfo.Name.Substring(0, 1);
                // خروجی بر حسب گیگابایت با یک عدد بعد از اعشار را برمیگردونه
                double driveTotalSize;
                DataUnit dataUnit = (VssBackup.ConvertByteToDataUnit(driveInfo.TotalSize, DataUnit.TeraByte, 2) >= 1) ? DataUnit.TeraByte : DataUnit.GigaByte;
                byte decimalNumber = (byte)((dataUnit == DataUnit.TeraByte) ? 2 : 1);
                driveTotalSize = VssBackup.ConvertByteToDataUnit(driveInfo.TotalSize, dataUnit, decimalNumber);
                // متن آیتم نهایی برای اضافه کردن به عنوان آیتم کنترلِ comboBox
                string itemText = "Drive " + driveName;
                if (driveInfo.VolumeLabel != null && driveInfo.VolumeLabel != "")
                    itemText += " [" + driveInfo.VolumeLabel + "] ";
                itemText += " - " + driveTotalSize + " ";
                itemText += (dataUnit == DataUnit.TeraByte) ? "TB" : "GB";

                ComboBoxItem comboBoxItem = new ComboBoxItem();
                comboBoxItem.Content = itemText;
                comboBoxItem.Tag = driveInfo;
                comboBox.Items.Add(comboBoxItem);
            }

این متد در لایه ی View تعریف شده .
هنوز کامل قوانینِ MVVM را براش رعایت نکردم (در حال درست کردنم) .
همونطور که مشخص هست ، مقدار نهایی ای که نیاز هستن ، متغییر driveTotalSize و همچنین متغییر dataUnit (که توسط اش بتونیم مشخص کنیم که متن مون "TB" باشه یا "GB" باشه) هستند .
برای بدست آوردن مقدار driveTotalSize ، خوب میتونم کدها را به Model منتقل کنم .
اما باز به متغییر dataUnit نیاز هست در این متد (View) .

تشکر استاد .
 
آخرین ویرایش:

the_king

مدیرکل انجمن
خیلی ممنون استاد از جواب تون .
استاد ، میگم در معماری MVVM ، در لایه ی View ، یه شی ای از نوعی که در Model تعریف میشه را میتونیم تعیین کنیم دیگه .
اگر منظورتون رو درست متوجه شده باشم، خیر، نمی توانید. هیچ ارجاع صریحی به نوع شیء که در Model تعریف شده نمی توانید داشته باشید، یعنی در هنگام کامپایل اون View نباید هیچ نیازی به وجود اون Model و تعریف نوع فلان که در Model تعریف شده باشه.
یعنی فرضا یه enum (یا حتی کلاس) ای را در Model مون تعریف کردیم ، حالا طبق محاسباتی که در متدی که در کلاسی که در Model مشخص کردیم ، اون متد ، مقداری از اون enum را برمیگردونه که این مقدار را در لایه ی View مون نیاز داریم (فرضا مقدارِ enum ئه مورد نظر را که بدست اومد را میخوایم در متغییرِ محلی در لایه ی View استفاده کنیم) .
اگر اون View برای کامپایل نیاز به اون تعریف enum/class داشته باشه که تعریفش در Model ئه، پس View به Model وابسته شده و نقض معماری MVVM رخ داده.
این کار را میشه انجام داد و مشکلی نداره دیگه؟
با توضیحاتی که می دهید مشکل داره.
یعنی میشه متغییر محلی ای (یا پروپرتی و ...) را در View ، از نوعِ enum (یا کلاس و ...) ای که در Model تعریف کرده بودیم ، بگیریم ؟
خیر. بارها در این مورد صحبت کرده ایم، چرا از نو باید همچین مساله ای رو مطرح کنید؟
چون من نیاز قطعی دارم که در View ام ، حداقل نوعِ اون enum را در متغییرم ذخیره کنم .
View قراره صرفا رابط کاربر باشه، چه کار می کنید که نیاز به ذخیره سازی داده واسط کاربر در متغیر در View است؟ و چه پردازشی انجام می دهید که نیاز ئه نوع داده صریحا مشخص بشه و object برای ارتباط اش با ViewModel کفایت نمی کنه؟ نمیدونم این نیاز قطعی چیه ولی به این فکر کنید که آیا کاری که انجام می دهید مربوط به View بوده یا کاری بوده که باید در ViewModel انجام بشه؟
الان آیا شما میگید که این کار شدنی هست اما نباید به اعضای اون enum دسترسی داشته باشم؟
به محض اینکه کدی بنویسید که به نوع داده مورد نظر اشاره کنه MVVM رو نقض کرده اید. View شما نباید به تعاریف Model وابسته باشه، این مشکل زمانی پیش میاد که تفکیک وظایف رو به درستی انجام نمی دهید، دارید در View کاری رو انجام می دهید که وظیفه View نیست.
بجاش اگه برای محاسباتی که نیاز باشه به اعضای اون enum بخوام دسترسی داشته باشم ، باید شیِ enum را که در متغییری ذخیره کرده بودم ، بفرستم به Model ، تا اونجا محاسبه کنم و نهایتا مقدارِ آخری که ربطی به اعضای Model نداره (داده) را برگردونم؟

بذارید واضح تر بگم .
کدم اینه :

C#:
        public void FillComboBoxByDriveInfos(ComboBox comboBox)
        {
            DriveInfo[] driveInfos = ExtensionMethodViewModel.GetFixedNtfsDrives();
            if (driveInfos == null || driveInfos.Length < 1)
                return;
            foreach (DriveInfo driveInfo in driveInfos)
            {
                // فقط اولین کاراکتر که نام درایو (بدون کاراکتر اسلش) هست را برمیگردونه
                string driveName = driveInfo.Name.Substring(0, 1);
                // خروجی بر حسب گیگابایت با یک عدد بعد از اعشار را برمیگردونه
                double driveTotalSize;
                DataUnit dataUnit = (VssBackup.ConvertByteToDataUnit(driveInfo.TotalSize, DataUnit.TeraByte, 2) >= 1) ? DataUnit.TeraByte : DataUnit.GigaByte;
                byte decimalNumber = (byte)((dataUnit == DataUnit.TeraByte) ? 2 : 1);
                driveTotalSize = VssBackup.ConvertByteToDataUnit(driveInfo.TotalSize, dataUnit, decimalNumber);
                // متن آیتم نهایی برای اضافه کردن به عنوان آیتم کنترلِ comboBox
                string itemText = "Drive " + driveName;
                if (driveInfo.VolumeLabel != null && driveInfo.VolumeLabel != "")
                    itemText += " [" + driveInfo.VolumeLabel + "] ";
                itemText += " - " + driveTotalSize + " ";
                itemText += (dataUnit == DataUnit.TeraByte) ? "TB" : "GB";

                ComboBoxItem comboBoxItem = new ComboBoxItem();
                comboBoxItem.Content = itemText;
                comboBoxItem.Tag = driveInfo;
                comboBox.Items.Add(comboBoxItem);
            }

این متد در لایه ی View تعریف شده .
هنوز کامل قوانینِ MVVM را براش رعایت نکردم (در حال درست کردنم) .
همونطور که مشخص هست ، مقدار نهایی ای که نیاز هستن ، متغییر driveTotalSize و همچنین متغییر dataUnit (که توسط اش بتونیم مشخص کنیم که متن مون "TB" باشه یا "GB" باشه) هستند .
برای بدست آوردن مقدار driveTotalSize ، خوب میتونم کدها را به Model منتقل کنم .
اما باز به متغییر dataUnit نیاز هست در این متد (View) .
پارامتر ورودی FillComboBoxByDriveInfos چیه؟ یک کنترل، پس جاش کجا می تونه باشه؟ در View. همچین متدی با اون پارامتر ورودی اصلا جاش در ViewModel نیست.
بجز بخش نهایی کد دارید یک مجموعه string میسازید که کاری با کنترل ها نداره. چه چیزی قراره از Model دریافت بشه؟ مقدار اون itemText ها، یک آرایه از string ها. که نه کاری با comboBox داره و نه View.
پس این کد های تولید کننده string ها باید کجا باشند؟ در یک متد یا مشخصه در Model، نه در View، نه در ViewModel. با این روال فعلی که نشون می دهید شما نیازی به VssBackup و ExtensionMethodViewModel و هر واسط دیگری در ViewModel و View ندارید، چرا باید اینکار ها خارج از Model انجام بشه؟ مگر تولید اون string به مقادیر داخل View وابسته بود؟ داخل foreach چه کاری با comboBox دارید؟ هیچی. شرطی هم ندارید که به تغییرات در View وابسته باشه. تا چند سطر آخر هیچ کاری به View نداشتید، بجز اون سطر های آخر هیچ ربطی به View نداشت که کدش در ViewModel یا View باشه. جاشون در Model ئه.

پس تا اینجای کار فقط یک متد یا مشخصه در Model دارید که یک آرایه از string ها بهتون تحویل میده و از VssBackup و DriveInfo و ... استفاده می کنه.

حالا چه چیزی قراره به View منتقل بشه؟ فقط مقدار یک آرایه از string ها. پس یک متد یا مشخصه ای در ViewModel خواهید داشت که بتونه از اون متد یا مشخصه که در Model تعریف شده، استفاده کنه و اون مجموعه string ها رو دریافت کنه و به View منتقل کنه. یعنی ViewModel فقط واسط ئه، خودش نه با VssBackup کاری داره و نه با GetFixedNtfsDrives و ...

اون چند سطر آخر هم که ComboBoxItem رو ایجاد می کنید و ComboBox رو پر می کنید، مربوط به View ئه، ابدا جاشون در ViewModel نیست. از ViewModel یک مجموعه string رو میگیره و در comboBox پر می کنه.
 

SajjadKhati

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

استاد ، من توی Window.Resources ، یه فایل xaml که استایل هام توش تعریف شده بود (فایل DarkStyleResource.xaml) را توسط مقداردهی به پروپرتیِ ResourceDictionary.MergedDictionaries ، الحاق کردم .

بعد در ادامه ی Window.Resources ، یعنی در خطِ بعد از ملحق کردنِ DarkStyleResource.xaml ، یه استایلِ دیگه ای از CheckBox را (بر اساسِ استایلِ چک باکسی که در DarkStyleResource.xaml تعریف شده بود) ، اضافه کردم .
یعنی کدش این طور شد :

XML:
    <Window.Resources>
        <ResourceDictionary>

            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/PoshtibangirTolo;component/Resource/Style_Template/DarkStyleResource.xaml"/>
            </ResourceDictionary.MergedDictionaries>

            <Style TargetType="{x:Type CheckBox}" BasedOn="{StaticResource {x:Type CheckBox}}">
                <Setter Property="HorizontalAlignment" Value="Left"/>
                <Setter Property="VerticalAlignment" Value="Center"/>
                <Setter Property="Margin" Value="0, 5"/>
            </Style>
            
        </ResourceDictionary>
    </Window.Resources>

اما چک باکس ها ، بر اساس این استایل کار نمیکنن و وقتی این (کدِ) استایل از CheckBox را اینجا اضافه میکنم ، استایلِ CheckBox ای هم که توی فایل DarkStyleResource.xaml نوشته بودم هم اِعمال نمیشه .

اما اگه همین کدِ استایلِ CheckBox را به کنترل های والدِ Window منتقل کنم (مثلا به Grid.Resource منتقل کنم) ، دیگه قشنگ کار میکنه .
همچنین اگه این کدِ استایلِ CheckBox را هم ننویسم هم درست کار میکنه .
فقط انگار زمانی مشکل ایجاد میشه که در جایگاهِ Window.Resources بنویسم .
یا نمیدونم ، شاید بخاطر اینکه زیرِ خطِ ResourceDictionary.MergedDictionaries مینویسم ، این طور باشه .


میدونید این مشکل برای چیه؟
یعنی چرا وقتی استایلِ CheckBox را اونجا مینویسم ، هیچ استایلی از چک باکس کار نمیکنه اما در Resource های کنترل های فرزندش مینویسم ، کار میکنه؟

چون ResourceDictionary.MergedDictionaries ، در خطِ بالای کدِ استایلم نوشته شد ، پس اول باید فایل (و کدهای درون) DarkStyleResource.xaml اجرا بشه . پس همه ی استایل هایی که توی این فایل ایجاد کردم را باید قبل از اجرای کدِ استایلِ CheckBox در خط بالا ، بشناسه دیگه . درست میگم؟

تشکر استاد .
 

the_king

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

استاد ، من توی Window.Resources ، یه فایل xaml که استایل هام توش تعریف شده بود (فایل DarkStyleResource.xaml) را توسط مقداردهی به پروپرتیِ ResourceDictionary.MergedDictionaries ، الحاق کردم .

بعد در ادامه ی Window.Resources ، یعنی در خطِ بعد از ملحق کردنِ DarkStyleResource.xaml ، یه استایلِ دیگه ای از CheckBox را (بر اساسِ استایلِ چک باکسی که در DarkStyleResource.xaml تعریف شده بود) ، اضافه کردم .
یعنی کدش این طور شد :

XML:
    <Window.Resources>
        <ResourceDictionary>

            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/PoshtibangirTolo;component/Resource/Style_Template/DarkStyleResource.xaml"/>
            </ResourceDictionary.MergedDictionaries>

            <Style TargetType="{x:Type CheckBox}" BasedOn="{StaticResource {x:Type CheckBox}}">
                <Setter Property="HorizontalAlignment" Value="Left"/>
                <Setter Property="VerticalAlignment" Value="Center"/>
                <Setter Property="Margin" Value="0, 5"/>
            </Style>
           
        </ResourceDictionary>
    </Window.Resources>

اما چک باکس ها ، بر اساس این استایل کار نمیکنن و وقتی این (کدِ) استایل از CheckBox را اینجا اضافه میکنم ، استایلِ CheckBox ای هم که توی فایل DarkStyleResource.xaml نوشته بودم هم اِعمال نمیشه .

اما اگه همین کدِ استایلِ CheckBox را به کنترل های والدِ Window منتقل کنم (مثلا به Grid.Resource منتقل کنم) ، دیگه قشنگ کار میکنه .
همچنین اگه این کدِ استایلِ CheckBox را هم ننویسم هم درست کار میکنه .
فقط انگار زمانی مشکل ایجاد میشه که در جایگاهِ Window.Resources بنویسم .
یا نمیدونم ، شاید بخاطر اینکه زیرِ خطِ ResourceDictionary.MergedDictionaries مینویسم ، این طور باشه .

میدونید این مشکل برای چیه؟
در یک ResourceDictionary، چه ترکیبی از چند مجموعه باشه و چه نباشه، کلید هایی که برای دسترسی به اعضاء بکار می روند منحصر بفرد هستند، یک ResourceDictionary نمیتونه با یک کلید مشابه چند تا مقدار رو نگه داره یا تحویل بده. برای همین اگر برای اعضاء کلید منحصر بفرد متفاوت از سایرین تعریف نکنید، نمی توانید فرضا برای نوع CheckBox پیش از یک مقدار داشته باشید.
یعنی چرا وقتی استایلِ CheckBox را اونجا مینویسم ، هیچ استایلی از چک باکس کار نمیکنه اما در Resource های کنترل های فرزندش مینویسم ، کار میکنه؟
چون هر کدوم از المنت ها یک مجموعه Resources مخصوص خودشون دارند و در هر کدوم میشه برای یک کلید یک مقدار تعریف کرد که مستقل از Resources سایر المنت ها است.
چون ResourceDictionary.MergedDictionaries ، در خطِ بالای کدِ استایلم نوشته شد ، پس اول باید فایل (و کدهای درون) DarkStyleResource.xaml اجرا بشه . پس همه ی استایل هایی که توی این فایل ایجاد کردم را باید قبل از اجرای کدِ استایلِ CheckBox در خط بالا ، بشناسه دیگه . درست میگم؟
برای بار چندم، XAML ها اجرا نمی شوند، XAML زبان توصیفی است. کد توصیف اجرا نمیشه. بله، قبل از اون پردازش می شوند و شما در ادامه با اون Style جدید جایگزینی انجام می دهید، یعنی Style ای با همون کلید ثبت می کنید.
 

SajjadKhati

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

خیلی ممنون استاد .
منظورتون تگِ ResourceDictionary که برای Window.Resources تعریف کردم ، هست؟
خوب کلا پروپرتیِ FrameworkElement.Resources ، از نوعِ ResourceDictionary هست دیگه .
پس ، ما ، چه مستقیما در این پروپرتی ، تگِ ResourceDictionary بنویسیم یا ننویسیم ، هر نوعی که در ریسورس بدیم ، wpf اتوماتیک شی ای از نوعِ ResourceDictionary را براش در نظر میگیره دیگه . این طور نیست؟


برای بار چندم، XAML ها اجرا نمی شوند، XAML زبان توصیفی است. کد توصیف اجرا نمیشه. بله، قبل از اون پردازش می شوند و شما در ادامه با اون Style جدید جایگزینی انجام می دهید، یعنی Style ای با همون کلید ثبت می کنید.

بله . من فراموش میکنم .
البته چون دقیقا جریانش را نمیدونم چیه ، واسه ی همین زود از یادم میره .
یعنی فرضا نمیدونم که از زمانی که کدهای xaml را مینویسیم ، تا زمان کمپایل و زمان اجرای برنامه ، چه اتفاقاتی برای کدهای xaml میافته .
البته اگه اشتباه نکنم گفته بودین که زمان کمپایل (یا زمان اجرا ، دقیقا یادم نیست) ، که کدهای xaml به کدهای baml تبدیل میشن که خود baml را هم زیاد نمیشناسم .

تشکر استاد .
 

the_king

مدیرکل انجمن
خیلی ممنون استاد .
منظورتون تگِ ResourceDictionary که برای Window.Resources تعریف کردم ، هست؟
خوب کلا پروپرتیِ FrameworkElement.Resources ، از نوعِ ResourceDictionary هست دیگه .
پس ، ما ، چه مستقیما در این پروپرتی ، تگِ ResourceDictionary بنویسیم یا ننویسیم ، هر نوعی که در ریسورس بدیم ، wpf اتوماتیک شی ای از نوعِ ResourceDictionary را براش در نظر میگیره دیگه . این طور نیست؟
تصور نکنید که اون نوشتن و ننوشتن تگ ResourceDictionary یک مساله اختیاری و با نتیجه یکسان ئه، یک انتخاب ئه با دو نتیجه متفاوت، دو تا کار متفاوت ئه. در خیلی از کد ها ممکنه نتیجه اش شبیه هم باشه اما کار یکسانی نیستند.
به موضوع بحث ربطی نداره اما درسته که نوع مشخصه Resources ئه ResourceDictionary است ولی توصیفی که برای نوشتن و ننوشتن تگ ResourceDictionary دارید به تعیین نوع شیء خودکار ربطی نداره، یک انتخاب برای مقدار دهی ئه که تاثیر این انتخاب میتونه خیلی اساسی و متفاوت باشه.
شما یک المنت دارید که یک مشخصه Resources داره که مقدار پیشفرضی داره و مقدار پیشفرض اش معمولا یک دیکشنری خالی است اما ممکنه بخاطر کد هایی خالی نباشه. در هر صورت دیکشنری ای رو از قبل داره، معمولا null نیستند. حالا شما یا اصلا به اون مشخصه دست نمی زنید و تغییرش نمی دهید، یا میایید به همون دیکشنری یکسری عضو اضافه می کنید، یا دیکشنری قبلی رو میندازید دور و برای اون مشخصه یک دیکشنری جدید تعریف می کنید. اضافه کردن عضو به اون دیکشنری قبلی ممکنه رخداد خاصی رو تحریک نکنه ولی تعریف کردن دیکشنری جدید به این معنا است که اولا هر روالی که برای رخداد تغییر اون مشخصه هست رو فعال می کنید، ثانیا ممکنه تاثیر یکسری کد هایی که در کلاس یا XAML برای Resources پیشفرض نوشته شده بوده رو باطل کنید، فرضا در اون دیکشنری پیشفرض اشیاء ای بودند که دیگه با جایگزینی یک دیکشنری جدید که اعضاء اش رو شما مشخص می کنید وجود ندارند. پس این انتخاب که المنت ResourceDictionary رو بنویسید یا ننویسید میتونه در نتیجه اجرا روی یک المنت تاثیر مهمی داشته باشه.
 

SajjadKhati

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

خیلی ممنون استاد .
آها ، در کل ، در هر دو حالت ، چه خودمون صریحا از تگِ ResourceDictionary در پروپرتیِ FrameworkElement.Resources استفاده کنیم یا نه ، شیِ ResourceDictionary براش در نظر گرفته میشه اما ، وقتی ما تگی جز ResourceDictionary بدیم ، اعضایی که مشخص کردیم ، به لیستِ شیِ ResourceDictionary ئه پیش فرضی که wpf براش تدارک دیده بود ، اضافه میشه .
اما اگه ما تگِ ResourceDictionary را استفاده کنیم که کلا شیِ ResourceDictionary ئه جدیدی را بهش دادیم .
و هر المنت در ResourceDictionary هم باید کلیدی متفاوت داشته باشه .
درست میگم؟
من فکر میکردم مقدار پیش فرضِ پروپرتیِ FrameworkElement.Resources ، مقدار null باشه .

تازه در مطلب زیر دیدم ، همین چیزی که گفتید نوشته بود :

One or more object elements, each of which defines a resource. Each resource property element within each ResourceDictionary must have a unique value for the x:Key Directive, which serves as the unique key when values are retrieved from the ResourceDictionary.

اما هر چی میچرخم ، در اون مطلب نگفت که اگه ما شیِ جدیدی از ResourceDictionary بدیم (یا از شیِ پیش فرضش استفاده کنیم) ، در قضیه ی کلید دادن ، تفاوتی میکنه یا نه (تا اون کدی که در پست 795 دادم ، چون 2 تا کلید از یک نوع داره که نوعِ CheckBox هست ، بنابراین در این دو شی از ResourceDictionary ، باعثِ تفاوتی در عملکرد ، میشه یا نه) .

تشکر استاد .
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
آها ، استاد الان انگار دقیق تر متوجه شدم .
همونطور که گفته بودید ، هر شی (تگ) از نوعِ ResourceDictionary که میدیم ، یا در واقع هر مقداری که به پروپرتیِ FrameworkElement.Resources میدیم (حالا چه مستقیما نوعِ ResourceDictionary یا غیر مستقیم ، هر نوعِ دیگه مثل Style و ... بدیم) ، باید حتما یک کلیدِ منحصر به فرد براش در نظر بگیریم .


طبعا اگه کلیدی براش در نظر نگیریم (مثلا برای استایلی که تعریف میکنیم ، کلیدی در نظر نگیریم) ، صرفا نوعش را به به عنوان کلید میشناسه .
بنابراین از این انواعی که کلیدی براشون در نظر نمیگیریم (مثل Style ای که در پست 795 تعریف شد) ، نمیشه در یک شی (یا یک تگ) که در Resource ئه یک المنت ، تعریف میکنیم ، چندین نوع از این نوع (چندین نوع از این Style هایی که از یک نوع هستن و کلیدِ منحصر به فردی ندارن) را تعریف کنیم .
بنابراین ، در یک Resource ، فقط یک نوع از اینها را میشه تعریف کرد .

در کدی که دادم بودم ، یعنی در کد پست 795 :

XML:
    <Window.Resources>
        <ResourceDictionary>

            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/PoshtibangirTolo;component/Resource/Style_Template/DarkStyleResource.xaml"/>
            </ResourceDictionary.MergedDictionaries>

            <Style TargetType="{x:Type CheckBox}" BasedOn="{StaticResource {x:Type CheckBox}}">
                <Setter Property="HorizontalAlignment" Value="Left"/>
                <Setter Property="VerticalAlignment" Value="Center"/>
                <Setter Property="Margin" Value="0, 5"/>
            </Style>
            
        </ResourceDictionary>
    </Window.Resources>

در پروپرتیِ Window.Resources ، از یک شی از ResourceDictionary استفاده شده (که در کد ، مشخص هست) .
اول میره DarkStyleResource.xaml را لود میکنه . این فایل ، شامل استایلی از نوعِ CheckBox هست که کلیدِ منحصر به فردی نداره .
بعد در ادامه ی خط ، به استایلِ دیگه ای از نوعِ CheckBox که باز هم کلید منحصر به فردی نداره ، میرسه .
چون دو استایل از یک نوع (نوعِ CheckBox) داریم که کلیدِ منحصر به فردی ندارن و چون هر دوشون ، در یک شی از ResourceDictionary تعریف شدن ، واسه ی همین ، درست اجرا نمیشه .

اما اگه استایلِ CheckBox در کد بالا را در Resource ئه یه المنتِ دیگه تعریف کنیم ، چون در یه شیِ دیگه از ResourceDictionary تعریف میشه و در اون شی از ResourceDictionary هم فقط یکبار تعریف شد (با توجه به اینکه کلید منحصر به فردی نداره) ، مشکلی پیش نمیاد .

همچنین در کد زیر :

XML:
            <Grid.Resources>
                <Style TargetType="{x:Type CheckBox}" BasedOn="{StaticResource {x:Type CheckBox}}">
                    <Setter Property="HorizontalAlignment" Value="Left"/>
                    <Setter Property="VerticalAlignment" Value="Center"/>
                    <Setter Property="Margin" Value="0, 5"/>
                </Style>

                <Style TargetType="{x:Type CheckBox}" BasedOn="{StaticResource {x:Type CheckBox}}">
                    <Setter Property="Background" Value="Blue"/>
                </Style>
            </Grid.Resources>

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

تشکر استاد .
 

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

بالا