سلامی مجدد
خیلی ممنون استاد .
اول (برای خودم به عنوان اینکه بعدا مورد یادآوری قرار بگیره) بگم که دو مقاله ی زیر (لینک اولی را در پست قبلی هم دادم) ، هر چند برای مبتدی ها نوشته شده اما وقتی هر دو مقاله با هم خونده شه ، نکات بسیار خوبی از mvvm توش گیر آدم میاد :
و
------------------------------------------
حالا ، در لینک دومی ، اون جور که متوجه شدم (و اگه اشتباه نکنم) ، میخواد بگه (بصورت علنی و صریح این رو نگفت اما عبارتی که من از منظورش برداشت کردم را دارم میگم) که از Command بجای رویدادها استفاده کنیم (این تیکه را صریح نگفت) .
چون Command را بصورت Binding استفاده میکنیم و Binding هم چون بصورت پویا و دینامیک هست (باز هم تا اینجا را صریح نگفت) ، اگه اروری هم بده (و پروپرتیِ ای که بهش Binding میکنیم ، وجود نداشته باشه) ، اروری پرتاب نمیکنه و باعث نمیشه که برنامه مون اجرا نشه . صرفا زمان اجرا ، هشدار میده که فلان پروپرتی وجود نداره :
کد:
We haven't added that command to the ViewModel yet - so that Binding isn't going to work, but there are no errors. If you spin it up with an f5 you will find it runs OK. This is because Bindings fail gracefully. A fact that can be useful sometimes but can easily catch out the unwary.
و همچنین :
کد:
It's looking at MainWindowViewModel for a public property which is an ICommand called AddTextCommand and not finding it. Unlike if you connected up an event handler in markup the binding fails gracefully and the app just carries on going.
من این مقاله را دیدم ، ازش این نتیجه را گرفتم که در بالا گفتم . یعنی بجای رویدادها ، از Command ها استفاده کنم مخصوصا برای پیاده سازی MVVM چون Command ها را Binding میکنیم و Binding هم چون پویا هستند ، جابجایی و انتقال کد را که یکی از اهداف مهم در MVVM هست را خیلی راحت تر میکنه .
اما وقتی مقاله ی زیر را فعلا تا نصفه خوندم (که لینک داده بودید) :
Learn about commanding, an input mechanism in Windows Presentation Foundation which provides input handling at a more semantic level than device input.
docs.microsoft.com
دیدم که هدف Command ها اصلا جایگزینی با رویدادها نیست و اصلا دو چیز کاملا متفاوتی هستند :
- اولا Command ها یک مکانیزم ورودی هستند و اصلا رویداد و یا کاری شبیه به رویداد برای جایگزین شدنِ رویداد ، انجام نمیدن پس نمیشه بجای رویداد ازشون استفاده کرد .
- دوما ، Command Sources یا اشیاء یا المنت هایی که Command ها را اجرا میکنن (و پروپرتیِ Command و ... دارند تا بتونیم command هامون را بهشون Binding کنیم) ، اون المنت هایی هستند که اینترفیسِ ICommandSource را پیاده سازی میکنن . المنت هایی که این اینترفیس را پیاده سازی کردن ، بسیار محدود هستند و چند تا از معروف ترین هاش ، المنت های ButtonBase و MenuItem و Hyperlink (و ریبون ها و چند تای دیگه) هستن .
یعنی عملا برای اِعمال Command ها ، محدودیت روی المنت های خاصی داریم (نه همه ی المنت ها) .
- سوما ، روی همین المنت ها ، فقط روی یک رویدادشون Command ها اجرا میشن . یعنی المنت های ButtonBase و MenuItem و Hyperlink ، فقط وقتی که کلیک بشن ، Command هایی که بهشون Binding کردیم را اجرا میکنن .
یعنی این طور نیست که روی همین المنت های محدود هم بتونیم طوری تعیین کنیم که اگه فلان رویدادش اتفاق افتاد ، بیاد Command ای که تعیین میکنیم را اجرا کنه :
کد:
ButtonBase, MenuItem, and Hyperlink invoke a command when they are clicked, and an InputBinding invokes a command when the InputGesture associated with it is performed.
خوب اینجا سئوال مهم و اساسی این پیش میاد که Command ها که جوری طراحی شدن که میشه اینها را Binding کرد و این ، بزرگ ترین مزیت براشون هست که جداسازیِ کدهایی که در متد Execute اش را مینویسیم ، از view را رقم بزنه ، خوب چرا جوری طراحی نکردن که این محدودیت ها را نداشته باشه؟
یعنی اولا محدود به چند المنت خاص و محدود نباشه و دوما مثلا برای اون المنت های ButtonBase و MenuItem و Hyperlink ، فقط برای رویداد کلیک شون نباشه و ما بتونیم تعیین کنیم که برای کدوم رویداد باشه؟
چون وقتی این محدودیت ها باشه ، پس Command ها که جایگزینِ رویدادها نمیشن . رویدادها را هم اگه استفاده کنیم ، چون handler ئه رویداد را به المنت ای متصل میکنیم ، انتقال کد یا آپدیتِ view (و حذف و اضافه کردنِ المنت جدید) را با مشکلاتِ بیشتری مواجه میکنه که باید وقت بیشتری برای درست کردن شون صرف کرد و کلا باعث میشه با استفاده از رویدادها ، هدف mvvm که جداسازی view از منطق تجاری هست ، کمرنگ تر بشه .
یه سئوال دیگه اینکه با این همه محدودیت ای که Command ها دارن ، پس عملا در mvvm ، کاربرد بسیار محدودی دارن که و حتی اگه استفاده هم کنیم ، باز فایده ی چندانی نداره که . درست میگم؟
چون فرض کنید در پروژه ای 100 تا المنت مختلف دارید و 500 تا از رویدادهاشون که مختلف هم هستند ، کد دارند . حالا فرضا 20 تا از این المنت ها ، button باشن . 20 تا هم رویداد کلیک برای دکمه داشته باشید که بجای رویداد ، از Command براشون استفاده کرده باشید .
تکلیف بقیه ی رویدادهای دکمه هایی که استفاده کردید چی میشه؟
همچنین تکلیف بقیه ی المنت ها و رویدادهاشون (فرضا المنت combobox و grid و ...) که Command نمیتونن انجام بدن چی میشه؟
شما وقتی 500 تا رویداد دارین ، فقط 20 تاش را از Command استفاده کنید و 480 تای دیگه را از رویداد استفاده کنید ، (حتی اگه بر عکس باشه و فرضا 480 تا از Command و 20 تا را از رویداد استفاده کنید) ، در هر صورت ، باز view و المنت ها را به رویداد متصل کردید که باعث میشه جداسازی (منطق تجاری از view) ، پویا نباشه .
یعنی میخوام بگم فرضا حتی یه دونه از 500 تا را هم از رویداد استفاده کنیم ، باز باعث میشه کار خراب بشه . پس در این صورت فرقی نداره که دیگه از Command ها استفاده کنیم .
درست میگم؟
----------------------------------------------
استاد ، من هنوز 2 چیز را دقیق در mvvm متوجه نشدم (البته در حال خوندن مقاله ها و پیگیری کردن هستم چون اگه بگید جستجو نمیکنم) .
اینکه در پست 670 که پروژه ی mvvm داده بودم که از درون کلاس ViewModel ، پروپرتی ای از نوع Model (که نام و نوعش Student بود) در نظر گرفت . یکی از سئوال هام اون موقع این بود که آیا میشه از view ، به اعضایِ پروپرتیِ Student که در ViewModel هست ، دسترسی داشته باشیم (که mvvm را هم نقض نکرده باشه) ؟
اما من یه چیزی شبیه این رو در یه مثالی دیدم که اگه اشتباه نکنم ، یه همچین کاری را با Binding کردن انجام داد . لینک زیر :
Commands provide a mechanism for the view to update the model in the MVVM architecture. Commands provide a way to search the element tree for a command handler.
www.c-sharpcorner.com
اون قسمت از کد که :
XML:
<GridView>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Header="Address" Width="200" DisplayMemberBinding="{Binding Address}"/>
</GridView>
یا یه کم بالاتر اش ، که در کنترل Button ، مقدار Path را بصورت Path=SelectedItem.Address نوشت (البته برای ListView ، پروپرتیِ SelectedItem نداریم بلکه SelectedItems داریم که نمیدونم حالا اشتباه تایپی داشت یا نه) .
اگه اشتباه نکنم ، Binding کردن ، چون پویا هست ، مشکلی نداشته باشه . دقیق نمیدونم .
حالا باید بیشتر مقالات را ببینم .
---------------------------------------
سئوال بعدی هم که هنوز حل نشده اینه که وقتی در لایه ی Model و ViewModel ، اینترفیس INotifyPropertyChanged را پیاده سازی میکنن (فرض کنید این پیاده سازی در کلاس مربوط به Model انجام شد) ، خوب در کلاس مربوط به ViewModel ، از رویداد PropertyChanged که درون Model پیاده سازی شد ، باید اتصال انجام داده بشه و رویداد PropertyChanged را به handler ای متصل کنیم دیگه . درسته؟
اگه درسته ، من هیچ جا ندیدم که مثلا در لایه ی ViewModel یا View ، این رویداد را که در لایه ی ViewModel یا Model پیاده سازی کردن ، بخوان به handler ای متصل کنن .
وقتی اتصال به رویداد انجام نشه ، این که متدی را اجرا نمیکنه تا بهشون پیامی بده . پس چجوری کار میکنه؟!!
ببخشید استاد که بسیار طولانی شد .
تشکر