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

SajjadKhati

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



یعنی در مثال این پروژه :

XML:
        <ListView Margin="0, 240, 0, 0" ItemsSource="{Binding Path=StudentsForListView}">
            <ListView.View>
                <GridView>
                    <GridView.Columns>
                        <GridViewColumn Width="200" Header="First Name" DisplayMemberBinding="{Binding FirstName}" />
                        <GridViewColumn Width="200"  Header="Last Name" DisplayMemberBinding="{Binding LastName}"/>
                    </GridView.Columns>
                </GridView>
            </ListView.View>
        </ListView>

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

تشکر استاد .
 

SajjadKhati

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

تشکر استاد .

سلامی مجدد استاد .
درباره ی این سئوال که به جواب رسیدم و جوابش اینه که از طریق رویداد MouseEnter ئه ListViewItem میتونیم این کار را انجام بدیم .
اما دسترسی به شیِ ListViewItem از طریق شیِ ListView این صور هست که :
در کد سی شارپ ، میتونیم از متدِ ListView.ItemContainerGenerator.ContainerFromIndex ، به شیِ ListViewItem برسیم.
در xaml هم میتونیم درون ListView مون ، با Style دادن به نوع ListBoxItem ، و توسط EventSetter این کار را کنیم :



XML:
    <ListView >
        <ListView.ItemContainerStyle>
            <Style TargetType="{x:Type ListBoxItem}">
                <EventSetter Event="MouseEnter" Handler="ListBoxItem_MouseEnter" />
            </Style>
        </ListView.ItemContainerStyle>
    </ListView>

که البته باید آیتم های ListView ئه کد در بالا را هم حالا با پروپرتیِ View یا Source و ... ، پر کنیم .


==============================


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

متوجه ی منظورم شدید استاد؟
کلا قضیه ی همچین چیزی ، چطور میشه؟ همچین چیزی برای MVVM اشکال داره یا نه؟
اگه اشکال داره ، اگه به همچین متدی در Model احتیاج داشته باشیم ، چی کار باید کنیم (تا MVVM نقض نشه) ؟

تشکر استاد
 

the_king

مدیرکل انجمن
درسته که DataContext ئه ListView را شی ای از StudentViewModel تنظیم کردیم و هست اما wpf بصورت اتوماتیک ، آیتم های این ListView که همون GridViewColumn هستند را به شی ای که در جنریکِ Source (پروپرتیِ ItemsSource) اش که مشخص کردیم ، یعنی به شیِ Student مقداردهی میکنن .
درست میگم؟
متوجه نمی شوم، چرا میگید اما؟ مگه تناقضی هست؟ ظاهر جدا است، منبع داده هم جداست. ListView یک منبع داده داره مثل اون StudentsForListView که آیتم های داخلش رو باید لیست کنه و بصورت خودکار اعضاء داخل اون منبع داده برای ListViewItem های داخلش منبع داده می شوند. و ListView برای آیتم های داخلش یک توصیف ظاهر داره مثل اون GridViewColumn ها که منبع داده شون میتونه هر چیزی باشه، مثل FirstName یک آیتم داخل StudentsForListView. اینکه چه اطلاعاتی رو نشون بده خودتون در Binding ها مشخص می کنید. و هر کدوم از اعضاء اون StudentsForListView بصورت متعارف منبع داده اون ListViewItem هایی هستند که باید داخل لیست نمایش داده بشن، مگر اینکه به هر دلیلی بخواهید اطلاعات دیگری رو در آیتم ها نمایش بدهید.

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

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
متوجه نمی شوم، چرا میگید اما؟ مگه تناقضی هست؟ ظاهر جدا است، منبع داده هم جداست. ListView یک منبع داده داره مثل اون StudentsForListView که آیتم های داخلش رو باید لیست کنه و بصورت خودکار اعضاء داخل اون منبع داده برای ListViewItem های داخلش منبع داده می شوند. و ListView برای آیتم های داخلش یک توصیف ظاهر داره مثل اون GridViewColumn ها که منبع داده شون میتونه هر چیزی باشه، مثل FirstName یک آیتم داخل StudentsForListView. اینکه چه اطلاعاتی رو نشون بده خودتون در Binding ها مشخص می کنید. و هر کدوم از اعضاء اون StudentsForListView بصورت متعارف منبع داده اون ListViewItem هایی هستند که باید داخل لیست نمایش داده بشن، مگر اینکه به هر دلیلی بخواهید اطلاعات دیگری رو در آیتم ها نمایش بدهید.

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

منظورتون از "اعضای داخل منبع داده" ، در این پروژه همون اعضای کلاس Student هست دیگه؟
تقریبا همون چیزی که من در پست قبل گفتم ، نیست؟ کلا اعضای کالکشن ای که تعریف کردیم (مثل همون اعضای StudentsForListView که همون Student میشه) ، به عنوان DataContext ئه آیتم ها ، یعنی DataContext ئه ListViewItem ها در نظر گرفته میشن .

Button در پروژه شما چیه؟ منبع داده است؟ قاعدتا نه. Button و سایر المنت های مشابه از اجزاء اون واسط کاربری در View شما است که قراره کاربر باهاشون کار کنه، پس داده محسوب نمیشه و طبعا چون داده نیست به Model ارتباطی نداره. پس دلیلی نداره که بخواهد به Model ارسال بشه. چه منطقی برای اینکار دارید که یک جزء از واسط کاربری رو به Model ارسال کنید؟

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

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


متدهایی مثل :
SetToolTipsDelayDurationForControls<T>(List<T> controls, int controlsDelayTime, int duration = -1) که T میتونه کنترل باشه .
این متد ، برای کنترل های داده شده در پارامتر اول ، تاخیرِ tooltip را اِعمال میکنه .

List<T> FindParentAllElements<T>(T parent) که باز هم T میتونه کنترل باشه .
این متد ، کنترل فرزند و نوادگان (در element tree) را برمیگردونه .

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

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

پیوست ها

  • UI.rar
    5.2 کیلوبایت · بازدیدها: 0

the_king

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

منظورتون از "اعضای داخل منبع داده" ، در این پروژه همون اعضای کلاس Student هست دیگه؟
در اون مثال بله، هر چیزی که اون منبع داده IEnumerable به عنوان اعضاء بر میگردونه.
تقریبا همون چیزی که من در پست قبل گفتم ، نیست؟ کلا اعضای کالکشن ای که تعریف کردیم (مثل همون اعضای StudentsForListView که همون Student میشه) ، به عنوان DataContext ئه آیتم ها ، یعنی DataContext ئه ListViewItem ها در نظر گرفته میشن .
بله، این توضیح الان تون رو متوجه می شوم، واضح و مشخص ئه. اما حتی با وجود توضیحی که الان دادید همچنان متن قبلی تون رو نمی تونم بفهمم.
حالا این کلاس ، جزء لایه ی Model محسوب میشه دیگه . درسته؟
نه. شما استخراج داده از View تون رو سخت یا آسون باید در همون View انجام بدهید و فقط داده استخراج شده رو به ViewModel ارسال کنید.
المنت های View که نباید قاطی پردازش Model بشوند. هر ارجاعی به المنت ها رو صرفا باید در View نگهدارید.
چون موقع طراحی کلاس ، قضیه ی mvvm را نمیدونستم .
خوب ، حالا این کلاس را بخوام در پروژه ی mvvm ام استفاده کنم ، داستانش چجوری میشه؟
در بهترین حالت هیچی، میذاریدش کنار، یعنی کل معماری فعلی رو نادیده می گیرید، و از نو با معلومات به روز شده تون طراحی اش می کنید و در همه بخش ها اون تفکیک View و Model و ViewModel رو در نظر می گیرید.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
در اون مثال بله، هر چیزی که اون منبع داده IEnumerable به عنوان اعضاء بر میگردونه.

بله، این توضیح الان تون رو متوجه می شوم، واضح و مشخص ئه. اما حتی با وجود توضیحی که الان دادید همچنان متن قبلی تون رو نمی تونم بفهمم.

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

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

ارجاع دادنِ کنترلی از View به لایه ی ViewModel که اشکالی نداره؟
درسته؟
چون View میتونه با ViewModel رابطه داشته باشه دیگه .

مثل این پروژه ی زیر (باز هم یه کوچولو به روز کردم) ، متد ListViewItemMouseEnterMethod در لایه ی ViewModel که sender که کنترلِ ListView هست ، از رویداد ListViewItem_MouseEnter که درون View هست ، براش ارسال شد .

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

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

تشکر استاد .
 

پیوست ها

  • MVVM_Practies.rar
    1.9 مگایابت · بازدیدها: 0

the_king

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

SajjadKhati

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

سلامی مجدد
خیلی ممنون استاد از نکته ی بسیار خوب تون .
این نکات را انگار میدونستم . انگار حس میکنم شبیه این نکات (حالا شاید همین متن نبوده باشه) را قبلا گفتید اما نمیدونم از شناخت کم ام نسبت به mvvm هست یا چیز دیگه ای که تا این نکات مهم را در این پست نگفتید ، حواسم نبود یا فراموش کردم که ViewModel ، برای ارتباط بین View و Model هست (و خودش کاری نمیکنه جز ارتباط دادن اون دو لایه) پس نباید مثل View ، کنترل و المنت (بصری و ...) را بهش منتقل کنیم (چون Model ، کارش ، کار کردن با کنترل نیست) و همونطور که گفتید نه روال های دیتابیس و ... را منتقل کنیم . بلکه فقط داده باید بین این دو منتقل بشه .

البته یه استثناء وجود داره اون هم بجز زمانی که از Command (یا Binding) استفاده میکنیم . چون Command ها مستقیما درون ViewModel هستند و اگه پارامتری از یه کنترل را که بخوایم جدا کنیم ، خیلی وقت ها شاید نشه یا بسیار سخت بشه .


فرضا در این پروژه ای که (باز هم یه کم تغییر دادم) ، متد MouseMoveAssociateEventToCommandHandler در StudentViewModel که به Command ای متصل هست ، یه ورودی از نوع MouseEventArgs دریافت میکنه . چون ما میخوایم posation ئه مربوط به موس در روی اون دکمه را بگیریم . واسه ی همین پروپرتیِ PassEventArgsToCommand ئه مربوط به EventToCommand اش را true کردیم تا EventArgs ئه رویداد دکمه را به هندلر ئه Command مون منتقل کنه .

و در این متد هم از e.Source به عنوان شیِ دکمه استفاده کردیم (برای گرفتن posation اش) .
در این حالت ، اشکالی نداره . درست میگم؟

وقتی کنترل واسط کاربری رو به ViewModel ارسال می کنید چیزی که به واسط کاربری مربوطه رو داخل ViewModel منتقل نکرده اید؟

بله .

متوجه شدم .

نمیشه چیزی که مربوط به ViewModel نیست رو از View داخل ViewModel منتقل کنید و تفکیک MVVM رعایت شده باشه.

فقط همین؟ وظایف View باید از وظایف ViewModel تفکیک شده باشه، ViewModel که نباید درگیر کنترل واسط کاربری باشه.

بله .

اگر قرار بود ViewModel درگیر کنترل های واسط کاربری باشه که وجود ViewModel برای چی لازم بود؟ حذفش می کردند و بجایش View می ماند و Model.

قرار نیست همه چی در کلاس View ادغام بشه، چیزی که مربوط به View است در View، چیزی که مربوط به Model ئه در Model و بخش تبادل داده بین ایندو در ViewModel. در View داده ها رو از واسط کاربری استخراج کنید، در ViewModel اون داده ها رو دریافت کنید و به Model انتقال بدهید و برعکس.

اگر فکر می کنید باید همه چی در یک کلاس یا یک لایه باشه چه اصراری دارید که MVVM رو بکار ببرید؟ در MVVM تفکیک یک مورد ضروری ئه.
بله .

=============================

استاد ، در رویداد ListViewItem_MouseEnter در View ، اشکالی نداره که وقتی ListViewItem.Content مون که شیِ Student هست (و از نوع object هست) را در همین رویداد (که جزء View محسوب میشه) ، به نوعِ Student (که نوعِ Model مون هست) تبدیل کنیم دیگه . درست میگم؟
زمانی اشکال بوجود میاد که درون View (مثلا درون همین رویداد ListViewItem_MouseEnter) ، بخوایم به اعضای این شی که به نوعِ Student تبدیل کردیم (یعنی به اعضای Model مون) دسترسی پیدا کنیم .
درست میگم؟


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

پیوست ها

  • MVVM_Practies.rar
    1.9 مگایابت · بازدیدها: 1
آخرین ویرایش:

the_king

مدیرکل انجمن
سلامی مجدد
خیلی ممنون استاد از نکته ی بسیار خوب تون .
این نکات را انگار میدونستم . انگار حس میکنم شبیه این نکات (حالا شاید همین متن نبوده باشه) را قبلا گفتید اما نمیدونم از شناخت کم ام نسبت به mvvm هست یا چیز دیگه ای که تا این نکات مهم را در این پست نگفتید ، حواسم نبود یا فراموش کردم که ViewModel ، برای ارتباط بین View و Model هست (و خودش کاری نمیکنه جز ارتباط دادن اون دو لایه) پس نباید مثل View ، کنترل و المنت (بصری و ...) را بهش منتقل کنیم (چون Model ، کارش ، کار کردن با کنترل نیست) و همونطور که گفتید نه روال های دیتابیس و ... را منتقل کنیم . بلکه فقط داده باید بین این دو منتقل بشه .

البته یه استثناء وجود داره اون هم بجز زمانی که از Command (یا Binding) استفاده میکنیم . چون Command ها مستقیما درون ViewModel هستند و اگه پارامتری از یه کنترل را که بخوایم جدا کنیم ، خیلی وقت ها شاید نشه یا بسیار سخت بشه .
Command خودش جزئی از واسط کاربری نیست، Command یک کلاس ئه که قراره بر اساس یک ورودی کاری رو انجام بده، نه میدونه sender اش که منجر به اجرای Command میشه کدوم کنترل ئه و نه اهمیتی بهش میده. یعنی خودش کاری به واسط کاربری نداره، الزاما هم فراخوان اش واسط کاربری نیست. واسط کاربری ئه که بصورت متعارف ازش استفاده می کنه اما Command به واسط کاربری وابسته نیست و ازش جداست. برای همین اینکه Command در ViewModel باشه مشکلی نداره.
فرضا در این پروژه ای که (باز هم یه کم تغییر دادم) ، متد MouseMoveAssociateEventToCommandHandler در StudentViewModel که به Command ای متصل هست ، یه ورودی از نوع MouseEventArgs دریافت میکنه . چون ما میخوایم posation ئه مربوط به موس در روی اون دکمه را بگیریم . واسه ی همین پروپرتیِ PassEventArgsToCommand ئه مربوط به EventToCommand اش را true کردیم تا EventArgs ئه رویداد دکمه را به هندلر ئه Command مون منتقل کنه .و در این متد هم از e.Source به عنوان شیِ دکمه استفاده کردیم (برای گرفتن posation اش) .
در این حالت ، اشکالی نداره . درست میگم؟
قبلا هم گفتم، اشکال قضیه در اینه که شما استخراج X و Y از کنترل رو برده اید داخل ViewModel. این ViewModel نیست که باید از کنترل داده استخراج کنه، اون View است که باید خودش از کنترل هایش داده استخراج کنه. ViewModel باید فقط داده بگیره. اگر استخراج X و Y رو در Command ای انجام بدهید که در View باشه، می توانید اون رشته FirstName و LastName ای که بر اساس X و Y در Command میسازید رو به یک روالی در ViewModel منتقل کنید تا در مشخصه هایش ثبت کنه. فرقی هم نمی کنه که X و Y رو ارسال کنید یا رشته ها رو، چون عدد و رشته به هر حال داده است و مستقل از واسط کاربری.
استاد ، در رویداد ListViewItem_MouseEnter در View ، اشکالی نداره که وقتی ListViewItem.Content مون که شیِ Student هست (و از نوع object هست) را در همین رویداد (که جزء View محسوب میشه) ، به نوعِ Student (که نوعِ Model مون هست) تبدیل کنیم دیگه . درست میگم؟
نباید همچین کاری رو انجام بدهید. مدام دارم تکرار می کنم، در View نباید هیچ کدی صریحا به Model اشاره کنه، چون موقع کامپایل View رو وابسته می کنه به Model.
زمانی اشکال بوجود میاد که درون View (مثلا درون همین رویداد ListViewItem_MouseEnter) ، بخوایم به اعضای این شی که به نوعِ Student تبدیل کردیم (یعنی به اعضای Model مون) دسترسی پیدا کنیم .
فرقی نمی کنه. خود Student همونقدر در Model ئه که اعضاء اش.
نه متاسفانه. مطالب قبلی رو از نو مرور کنید.
 

SajjadKhati

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

قبلا هم گفتم، اشکال قضیه در اینه که شما استخراج X و Y از کنترل رو برده اید داخل ViewModel. این ViewModel نیست که باید از کنترل داده استخراج کنه، اون View است که باید خودش از کنترل هایش داده استخراج کنه. ViewModel باید فقط داده بگیره.

اگر استخراج X و Y رو در Command ای انجام بدهید که در View باشه، می توانید اون رشته FirstName و LastName ای که بر اساس X و Y در Command میسازید رو به یک روالی در ViewModel منتقل کنید تا در مشخصه هایش ثبت کنه. فرقی هم نمی کنه که X و Y رو ارسال کنید یا رشته ها رو، چون عدد و رشته به هر حال داده است و مستقل از واسط کاربری.

سلامی مجدد
خیلی ممنون استاد .
این مطالبی که گفتید (و بولد کردم) ، منظورتون پیاده سازیِ این روشی هست که در زیر میگم؟ :

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

اما در این صورت مجبور میشیم که DataContext را برای binding کردن به command برای اون دکمه ، هر بار تغییر بدیم (که این خودش جلوه ی خوبی به برنامه نمیده . فرض کنید 30 تا دکمه داریم ، DataContext ئه 20 تاشون که همونطور در Window مشخص کردیم ، شیِ ViewModel باشه اما DataContext ئه 10 تاشون را مجددا درون همون دکمه ها هر بار تغییر بدیم) .

بعد هم در Command ئه درون View مون ، شیِ المنت (مثلا شیِ Button) را بگیریم و داده اش را استخراج کنیم و بعد اون داده را به متدِ مورد نظری که درونِ ViewModel نوشتیم ، فراخونی کنیم و بفرستیم .
منظورتون اینهایی هست که در بالا گفتم؟

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

اگه آره ، خوب بدیش اینه که همونطور که گفتم ، برای هر المنت ای که بخوایم این کار را کنیم و command اش را درون View بنویسیم ، DataContext ئه همه ی اون المنت ها را باید مجزا تغییر بدیم .

اما در این مواقع ضروری ، اشکالی نداره هر نوع داده را از View به ViewModel انتقال بدیم . درسته که کارشون مجزاست و بهتره که کار با المنت ها درون View انجام بگیره اما باعث نمیشه که MVVM را نقض کنه . درست میگم؟ از در هم شدن کدها (قضیه ی همون DataContext) هم جلوگیری میشه .
چون بالاخره ViewModel ، لایه ای هست که بیشترین تغییرات در اونجا صورت میگیره . اغلب با تغییر دادنِ Model یا View ، لازم میشه که ViewModel را هم تغییر بدیم .


نباید همچین کاری رو انجام بدهید. مدام دارم تکرار می کنم، در View نباید هیچ کدی صریحا به Model اشاره کنه، چون موقع کامپایل View رو وابسته می کنه به Model.

فرقی نمی کنه. خود Student همونقدر در Model ئه که اعضاء اش.

نه متاسفانه. مطالب قبلی رو از نو مرور کنید.


بله . متوجه شدم . تصحیح اش کردم .
خیلی ممنون استاد .
 

the_king

مدیرکل انجمن
اول اینکه پروپرتی های از نوع Command را معمولا در ViewModel میزارن (به نظرم چون متد Execute ، اغلب نیاز داره که با اعضای Model در ارتباط باشه و وظیفه ی ارتباط برقرار کردن هم با ViewModel هست) .
نه، فرضا یک Command دارید که View رو به شیوه ای Full Screen می کنه، هیچ کاری هم با Model نداره، پس دلیلی نداره که همه Command ها با Model کاری داشته باشند. اون Command ای هم که در View است و میخواد داده ای رو به Model ارسال کنه باید با چی در ارتباط باشه؟ ViewModel، نه Model. اینکه روال مشخصی داره.
حالا اگه بخوایم Command مون را توی View قرار بدیم ، پس همونطور که گفتید ، یه متدی را باید توی ViewModel بسازیم که از توی (متدِ) Command مون ، فراخونی اش کنیم (برای اینکه با Model مون ارتباط برقرار کنه) .
بله، دقیقا و هر چقدر متد عمومی تری بنویسید که بدرد Command ها یا روال بیشتری بخوره طراحی بهتری انجام داده اید، یعنی سعی کنید حجم و پیچیدگی کمتری در ViewModel داشته باشید، برای کار های مشابه چندین متد شبیه به هم نسازید.
اما در این صورت مجبور میشیم که DataContext را برای binding کردن به command برای اون دکمه ، هر بار تغییر بدیم (که این خودش جلوه ی خوبی به برنامه نمیده . فرض کنید 30 تا دکمه داریم ، DataContext ئه 20 تاشون که همونطور در Window مشخص کردیم ، شیِ ViewModel باشه اما DataContext ئه 10 تاشون را مجددا درون همون دکمه ها هر بار تغییر بدیم).
متوجه صورت مساله نمی شوم، DataContext از چی به چی و چرا باید تغییر کنه؟
بعد هم در Command ئه درون View مون ، شیِ المنت (مثلا شیِ Button) را بگیریم و داده اش را استخراج کنیم و بعد اون داده را به متدِ مورد نظری که درونِ ViewModel نوشتیم ، فراخونی کنیم و بفرستیم .
اگر در Button تون داده هست، بله. مثلا اون Position داخل دکمه در مثال شما داده است، ولی معمولا دکمه خودش داده ای نداره.
منظورتون اینهایی هست که در بالا گفتم؟
اون بخش DataContext رو متوجه نمی شوم.
اما در این مواقع ضروری ، اشکالی نداره هر نوع داده را از View به ViewModel انتقال بدیم . درسته که کارشون مجزاست و بهتره که کار با المنت ها درون View انجام بگیره اما باعث نمیشه که MVVM را نقض کنه . درست میگم؟ از در هم شدن کدها (قضیه ی همون DataContext) هم جلوگیری میشه .
چه ضروری و چه غیر ضروری داده بین View و ViewModel و بین ViewModel و Model رد و بدل میشه، که عادی و بدون ایراد ئه. و هر انتقال اجزاء واسط کاربری هم به ViewModel چه ضروری و چه غیر ضروری ایراد داره و MVVM رو نقض می کنه، اگر بخواهید MVVM رو رعایت کنید بهانه ای برای استخراج داده از کنترل ها در ViewModel ندارید.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
نه، فرضا یک Command دارید که View رو به شیوه ای Full Screen می کنه، هیچ کاری هم با Model نداره، پس دلیلی نداره که همه Command ها با Model کاری داشته باشند.

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

بله . این رو که میدونم .
منظورم کامندِ MouseMoveAssociateEventToCommand و متدِ MouseMoveAssociateEventToCommandHandler (در پروژه ی قبلی) بود که اطلاعاتی که x و y ئه موس روی دکمه هست را به Model میخواد منتقل کنه .

اون Command ای هم که در View است و میخواد داده ای رو به Model ارسال کنه باید با چی در ارتباط باشه؟ ViewModel، نه Model. اینکه روال مشخصی داره.

بله .

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

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

متوجه صورت مساله نمی شوم، DataContext از چی به چی و چرا باید تغییر کنه؟

پروژه را دوباره برای اینکه منظورم را از تغییرِ DataContext برسونم نوشتم که در زیر آپلود میکنم .
به رویدادِ MyMainWindow_Loaded در View نگاه کنید . باید DataContext ئه اون کنترل و المنت ای که میخوایم به پروپرتی ای که در View هست ، binding کنیم ، تغییر بدیم دیگه . چون DataContext ئه پیش فرض را در Window ، شیِ ViewModel (در اینجا همون StudentViewModel) گرفتیم که به عنوانِ DataContext ئه همه ی کنترل ها و المنت های زیر فرزندان و نوادگانِ Window هم استفاده میشه و Source ئه تمامِ binding ها که همون DataContext شون میشه .

منظورم اینه که مثل مقدارِ :

C#:
        private void MyMainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            this.AssociateEventToCommandButton.DataContext = this;
        }

که تغییر دادیم ، باید تمامِ DataContext های کنترل های دیگه ای که میخوایم به Command هایی که درون View مینویسیم را هم تغییر بدیم .
علاوه بر این کد ، جلوه ی نامرتبی هم میگیره که فرضا یه بخشی از Command ها درون View باشن و بخشی دیگه درون ViewModel باشن . نه؟

البته نمیدونم در کد xaml ، چرا وقتی بجای کد بالا ، از کد زیر استفاده میکنم :

XML:
        <Button DataContext="{Binding ElementName=MyMainWindow}" Name="AssociateEventToCommandButton" Content="Mouse Move__Associate Event To Command" Margin="0, 140, 0, 0" Padding="5, 2" HorizontalAlignment="Left" VerticalAlignment="Top" Height="50" >
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="MouseMove">
                    <command:EventToCommand x:Name="AssociateEventToCommand" Command="{Binding Path=MouseMoveAssociateEventToCommand}"
                                            PassEventArgsToCommand="True"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>

در صورتی که نام Window را مقدار "MyMainWindow" میگیرم ، DataContext ئه Button ام کار نمیکنه (ارور نمیده ولی کار هم نمیکنه) . نمیدونم در xaml چجوری میشه مقدار DataContext ئه Button را برابر با Window ای که توش هستیم داد . شما میدونید استاد؟

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

XML:
                <i:EventTrigger EventName="MouseMove">
                    <command:EventToCommand x:Name="AssociateEventToCommand" Command="{Binding Path=MouseMoveAssociateEventToCommand}"
                                            PassEventArgsToCommand="True"/>
                </i:EventTrigger>

اگه در کدهای سی شارپ (نه کدهای xaml) ، بخوایم اون EventToCommand ای که نام اش AssociateEventToCommand هست ، برای پروپرتیِ Command اش (یعنی برای پروپرتیِ Command ئه EventToCommand) ، در کدهای سی شارپ همین Binding ای که در همین کدِ xaml انجام شد را انجام بدیم ، کدش چجوری میشه؟
چون کلاسِ EventToCommand ، مثل المنت ها و کنترل هایی مثل Button نیست که متد SetBinding را برای تنظیم کردن بایندینگ داشته باشه . در این صورت باید چی کار کرد؟


چه ضروری و چه غیر ضروری داده بین View و ViewModel و بین ViewModel و Model رد و بدل میشه، که عادی و بدون ایراد ئه. و هر انتقال اجزاء واسط کاربری هم به ViewModel چه ضروری و چه غیر ضروری ایراد داره و MVVM رو نقض می کنه، اگر بخواهید MVVM رو رعایت کنید بهانه ای برای استخراج داده از کنترل ها در ViewModel ندارید.

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

چون اگه مثل کامندِ MouseMoveAssociateEventToCommand در پروژه ام ، بخوایم بخشی از Command ها را که فقط برای ارتباط با واسط کاربری ، درون View بیاریم و از ViewModel جدا کنیم ، علاوه بر اون قضیه ی کدهای DataContext ، دو پارگی و دو قسمت شدنِ Command ها ، باعث پیچیدگیِ بیشترِ کد میشه .
در این صورت ، به احتمال زیاد ، استفاده از رویداد (بجای استفاده از Command ای که درونِ اون رویداد میخوایم اجرا کنیم) ، ترجیح داده شه .

=======================================

استاد در مقاله ی زیر :


برخلافِ اون لینکی که در پست 720 داده بودم و میگفت (وقتی Path را یه کالکشن انتخاب میکنیم) ، DataContext ئه همه ی آیتم های ItemControl (مثل ListView) ، یعنی DataContext ئه ListViewItem هاش را برابر با نوعِ داده ایِ اعضای اون کالکشن انتخاب میکنه .

اما در این مقاله ، یه کدی داد :

YAML:
<DockPanel DataContext="{x:Static Fonts.SystemFontFamilies}">
  <TextBlock DockPanel.Dock="Top"
             Text="{Binding Baseline}" />
  <ListBox ItemsSource="{Binding}"
           IsSynchronizedWithCurrentItem="True" />
</DockPanel>

که میگه Fonts.SystemFontFamilies ، کالکشنی از نوع FontFamily هست . و در پروپرتیِ Text ئه TextBlock ، به پروپرتیِ Baseline (که عضئی از کلاسِ FontFamily هست ، نه عضوی از کالکشن ها) ، binding انجام میده .
همچنان که دقت دارین ، DockPanel از نوع panel هست و نه ItemControl که ListViewItem یا ListBoxItem و اینها داشته باشه (که در اون لینک پست 720 در این باره صحبت کرد) .


بلکه در این مقاله میگه :

However, the TextBlock has a binding expression that seems to make no sense – it tries to read the Baseline property, and yet the source, an array, has no such property. When WPF encounters a binding to a non-existent property on a collection, WPF has a fallback strategy: it looks for the named property on the current item. Consequently, the TextBlock shows the Baseline property of the currently selected font.

وقتی که wpf به binding در یه کالکشن ای (به عنوان DataContext یا Source ئه Binding) برخورد میکنه که پروپرتی مورد نظر وجود نداره ، wpf برای نام اون پروپرتی (ای که موجود نبود) در current item و آیتم انتخاب شده ی اون کالکشن برای اون پروپرتی جستجو میکنه .

الان این درست هست . درست میگم؟ اون قبلی که گفت ، درست نیست . چون در اینجا DockPanel که از نوع ItemControl نیست و در Text ئه TextBlock هم این نوع binding انجام شد .

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

اما اینکه منظورش از current item یا آیتم انتخاب شده در کالکشن چی هست ، من یه کم جستجو کردم و یه چیزهای سطحی متوجه شدم اما نه کامل :


در مقاله ی بالا میگه :

The current item can theoretically be different from whichever the user has selected in a collectionview bound to a Selector but let's concentrate on situations when current means selected item.
The way to make sure the current item and selected item match one another is to use the Selector.IsSynchronizedWithCurrentItem property.

که میگه current item میتونه به معنای هر چیزی که کاربر در CollectionView ای که به کنترلِ Selector بایندینگ شده باشه ، نباشه (اما میتونه هم باشه) .
که با تنظیم پروپرتیِ Selector.IsSynchronizedWithCurrentItem به true میشه از همگامیِ این دو با هم مطمئن شد .


اما سئوال این هست که اگه کالکشن مون از نوع کلاسِ CollectionView نباشه (فرضا از نوع List یا ObservableCollection و ... باشه) ، و همچنین بخوایم عضوی از این کالکشن (فرضا current item از این کالکشن) را به پروپرتیِ یه المنتی جز Selector (مثلا پروپرتیِ یه Button یا مثل کد بالا ، به پروپرتیِ یه TextBlock) متصل کنیم ، در این صورت این current item ئه کالکشن مون ، اولا مقدارش را از کجا میگیره و از کجا مقداردهی میشه . یعنی از کجا متوجه بشیم که current item ئه کالکشن مون ، مقدارش به کدوم عضو از کالکشن مون اشاره میکنه (در صورتی که کالکشن مون CollectionView نباشه و فرضا از نوع List یا ObservableCollection باشه)؟

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

بعد این CollectionView (و کلاس های فرزندش) وقتی استفاده میشه که بخوایم به شیِ binding مون از مرتب سازی ، فیلترینگ یا گروه بندی (که دقیقا این دو تای آخر را نمیدونم چیه) ای که در کالکشن مون اتفاق افتاد ، اطلاع بدیم؟
میشه بجاش از همون ObservableCollection استفاده کنیم و کالکشن مون را مرتب کنیم و کالکشنِ مرتب شده را بهش مجددا شیِ جدیدی بدیم . (هر چند اصولی شاید نباشه) . درست میگم؟

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

پیوست ها

  • MVVM_Practies.rar
    1.9 مگایابت · بازدیدها: 1
آخرین ویرایش:

the_king

مدیرکل انجمن
منظورتون اینه که برای ViewModel ، صرفا در حد انتقال داده ، کدمون را بنویسیم . نه اینکه کار و کدهای Model را انجام بده (یعنی منطق و محاسباتی را انجام بده) و نه کاری با کنترل ها که کار View هست ، داشته باشه.
بله.
پروژه را دوباره برای اینکه منظورم را از تغییرِ DataContext برسونم نوشتم که در زیر آپلود میکنم .
به رویدادِ MyMainWindow_Loaded در View نگاه کنید . باید DataContext ئه اون کنترل و المنت ای که میخوایم به پروپرتی ای که در View هست ، binding کنیم ، تغییر بدیم دیگه . چون DataContext ئه پیش فرض را در Window ، شیِ ViewModel (در اینجا همون StudentViewModel) گرفتیم که به عنوانِ DataContext ئه همه ی کنترل ها و المنت های زیر فرزندان و نوادگانِ Window هم استفاده میشه و Source ئه تمامِ binding ها که همون DataContext شون میشه .

منظورم اینه که مثل مقدارِ :

C#:
        private void MyMainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            this.AssociateEventToCommandButton.DataContext = this;
        }

که تغییر دادیم ، باید تمامِ DataContext های کنترل های دیگه ای که میخوایم به Command هایی که درون View مینویسیم را هم تغییر بدیم .
علاوه بر این کد ، جلوه ی نامرتبی هم میگیره که فرضا یه بخشی از Command ها درون View باشن و بخشی دیگه درون ViewModel باشن . نه؟
نه. به DataContent اون دکمه چیکار دارید؟ بذارید همون مقدار خودکار باشه، اصلا نیازی به اون this.AssociateEventToCommandButton.DataContext = this نیست. وقتی اون کد رو حذفش کردید چه شرایطی دارید؟
شما یک پنجره دارید که همون اول کار برایش یک StudentViewModel رو به عنوان DataContent در نظر گرفته اید. تا اینجا درست.
بعد داخلش یک دکمه دارید که EventToCommand ای داره که قراره Bind کنه روی Path=MouseMoveAssociateEventToCommand
XML:
Command="{Binding Path=MouseMoveAssociateEventToCommand}"
حالا Source برای این Binding چیه؟ بصورت پیشفرض DataContext ئه. در StudentViewModel میگرده دنبال اون MouseMoveAssociateEventToCommand و پیداش نمی کنه و برای همین کار نخواهد کرد. ایراد در چیه؟ در اینکه Source ئه Binding مشخص نشده، نه اینکه View تون با DataContext اشتباهی کار می کنه.
Source اش رو درست تنظیم کنید تا درست بشه :
XML:
Command="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=MouseMoveAssociateEventToCommand}"
البته نمیدونم در کد xaml ، چرا وقتی بجای کد بالا ، از کد زیر استفاده میکنم :

XML:
        <Button DataContext="{Binding ElementName=MyMainWindow}" Name="AssociateEventToCommandButton" Content="Mouse Move__Associate Event To Command" Margin="0, 140, 0, 0" Padding="5, 2" HorizontalAlignment="Left" VerticalAlignment="Top" Height="50" >
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="MouseMove">
                    <command:EventToCommand x:Name="AssociateEventToCommand" Command="{Binding Path=MouseMoveAssociateEventToCommand}"
                                            PassEventArgsToCommand="True"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>

در صورتی که نام Window را مقدار "MyMainWindow" میگیرم ، DataContext ئه Button ام کار نمیکنه (ارور نمیده ولی کار هم نمیکنه) . نمیدونم در xaml چجوری میشه مقدار DataContext ئه Button را برابر با Window ای که توش هستیم داد . شما میدونید استاد؟
نباید هم کار کنه، چون Command رو وقتی روی MyMainWindow.MouseMoveAssociateEventToCommand ئه Bind می کنه که مقدار MouseMoveAssociateEventToCommand اش همون مقدار پیشفرض null ئه. Command اش null می مونه.
و همچنین استاد در کد زیر :

XML:
                <i:EventTrigger EventName="MouseMove">
                    <command:EventToCommand x:Name="AssociateEventToCommand" Command="{Binding Path=MouseMoveAssociateEventToCommand}"
                                            PassEventArgsToCommand="True"/>
                </i:EventTrigger>

اگه در کدهای سی شارپ (نه کدهای xaml) ، بخوایم اون EventToCommand ای که نام اش AssociateEventToCommand هست ، برای پروپرتیِ Command اش (یعنی برای پروپرتیِ Command ئه EventToCommand) ، در کدهای سی شارپ همین Binding ای که در همین کدِ xaml انجام شد را انجام بدیم ، کدش چجوری میشه؟
چون کلاسِ EventToCommand ، مثل المنت ها و کنترل هایی مثل Button نیست که متد SetBinding را برای تنظیم کردن بایندینگ داشته باشه . در این صورت باید چی کار کرد؟
SetBinding هم نباشه BindingOperations.SetBinding که هست.
C#:
            Binding myBinding = new Binding("MouseMoveAssociateEventToCommand");
            myBinding.Source = this;
            BindingOperations.SetBinding(AssociateEventToCommand, EventToCommand.CommandProperty, myBinding);
 

the_king

مدیرکل انجمن
چرا با انتقال واسط کاربری و المنت و کنترل ها به ViewModel ، معماری MVVM نقض میشه؟
کافیه بهش فکر کنید. MVVM سه تا جزء تفکیک شده تعریف کرده، View و Model و ViewModel.
هیچکدوم هم ناحیه مشترک ندارند، کاملا از هم تفکیک شده اند، در نمودار اش هم مشخص هست.
اگر مشخصات و تعاریف این سه جزء از هم قابل تفکیک نباشند، سه جزء بودن معنی داره؟ طبعا نه.
حالا یک کلاسی رو در پروژه تون تصور کنید که داخلش واسط کاربری و کنترل ها مورد استفاده قرار گرفته و با جزء ViewModel در ارتباط ئه.
این کلاس به جزء ViewModel تعلق داره یا View یا Model؟
با منطق شما هم میتونه به ViewModel تعلق داشته باشه و هم View و احتمالا هم Model؟ چرا؟
چون برای وجود کنترل ها در ViewModel که ایرادی نمی بینید، پس اگر در ViewModel ایرادی نداشته باشه قاعدتا برای وجودش در Model نباید ایرادی بگیرید، البته خیلی هم مهم نیست که وجود اش در Model رو منطقی بدونید یا نه، همون که سر تعلق اش به View و ViewModel ابهام باشه کافیه.
از طرف دیگه اینکه یک جزء از ViewModel بتونه با سایر اجزاء ViewModel در ارتباط باشه مشکلی نداره، بالاخره اجزاء داخلی میتوانند با همدیگه تعامل داشته باشند، همونطور که Button با Grid و Window میتونه رابطه داشته باشه، غیر از اینه؟ پس میتونه متعلق به ViewModel باشه که با خودش در ارتباط ئه، مشکلی که نداره؟ این کلاس در View هم قطعا میتونه باشه، چون هم با واسط کاربری سر و کار داره و هم ارتباط View با ViewModel منطقی است. این هم که مشکلی نداره؟
میشه همچین چیزی که در پروژه شما View و ViewModel محدوده مشترک داشته باشند و همچنان تفکیک سه جزء معماری MVVM صورت گرفته باشه؟
توی مقالاتی که یه کم درباره ی MVVM خوندم ، فکر نکنم جایی در این باره حرفی زده باشن و اینکه در این صورت ، نقض کنه یا نکنه ، حرفی زده باشن .
استدلال تون اینطوریه، در مقالات به کررات در مورد اینکه عدد 32768 در متغیر های short / Int16 جا نمیشه و خطا میده و دلیلش حرف زده شده.
اما مقاله ای پیدا نمی کنید که در مورد این خطا برای عدد 32771 حرفی بزنه. نیست. پس میتونیم نتیجه بگیریم که احتمالا برای 32771 خطا رخ نمیده چون در مقالات در موردش حرفی نزده.
چون اگه مثل کامندِ MouseMoveAssociateEventToCommand در پروژه ام ، بخوایم بخشی از Command ها را که فقط برای ارتباط با واسط کاربری ، درون View بیاریم و از ViewModel جدا کنیم ، علاوه بر اون قضیه ی کدهای DataContext ، دو پارگی و دو قسمت شدنِ Command ها ، باعث پیچیدگیِ بیشترِ کد میشه .
این پیچیده تر شدن کد نقض چیه که به MVVM ربط داشته باشه؟ یا چیزی رو نقض می کنه که باید جلوش رو بگیریم؟ فکر نمی کنم اینطور باشه. وقتی شما راه بروید انرژی تون کم میشه. بدیهی است که راه رفتن منجر به از دست دادن انرژی میشه، پس نباید راه برویم؟ کد های در دسترس رو ببینید، در سایت github.com انواع کد ها هست؟ کدوم شون خیلی خیلی ساده است؟ همه شون تا حدی پیچیدگی دارند، این پیچیدگی چیزی است که بخاطر اجتناب ازش اصلا کد نویسی نشه؟ بدیهی است که کد بیشتری می نویسیم و پیچیدگی افزایش پیدا می کنه. پیچیدگی بیشتر میشه فاجعه ای رخ میده؟
در این صورت ، به احتمال زیاد ، استفاده از رویداد (بجای استفاده از Command ای که درونِ اون رویداد میخوایم اجرا کنیم) ، ترجیح داده شه .
هر فرد مستقل انتخاب می کنه، درسته؟ شما در مورد کدوم فرد صحبت می کنید؟ کدوم فرد ئه که رویداد رو بجای Command ترجیح میده؟ مهمه که بدونیم این فرد چی رو ترجیح میده؟
استاد در مقاله ی زیر :


برخلافِ اون لینکی که در پست 720 داده بودم و میگفت (وقتی Path را یه کالکشن انتخاب میکنیم) ، DataContext ئه همه ی آیتم های ItemControl (مثل ListView) ، یعنی DataContext ئه ListViewItem هاش را برابر با نوعِ داده ایِ اعضای اون کالکشن انتخاب میکنه .

اما در این مقاله ، یه کدی داد :

YAML:
<DockPanel DataContext="{x:Static Fonts.SystemFontFamilies}">
  <TextBlock DockPanel.Dock="Top"
             Text="{Binding Baseline}" />
  <ListBox ItemsSource="{Binding}"
           IsSynchronizedWithCurrentItem="True" />
</DockPanel>

که میگه Fonts.SystemFontFamilies ، کالکشنی از نوع FontFamily هست . و در پروپرتیِ Text ئه TextBlock ، به پروپرتیِ Baseline (که عضئی از کلاسِ FontFamily هست ، نه عضوی از کالکشن ها) ، binding انجام میده .
همچنان که دقت دارین ، DockPanel از نوع panel هست و نه ItemControl که ListViewItem یا ListBoxItem و اینها داشته باشه (که در اون لینک پست 720 در این باره صحبت کرد) .


بلکه در این مقاله میگه :



وقتی که wpf به binding در یه کالکشن ای (به عنوان DataContext یا Source ئه Binding) برخورد میکنه که پروپرتی مورد نظر وجود نداره ، wpf برای نام اون پروپرتی (ای که موجود نبود) در current item و آیتم انتخاب شده ی اون کالکشن برای اون پروپرتی جستجو میکنه .

الان این درست هست . درست میگم؟ اون قبلی که گفت ، درست نیست . چون در اینجا DockPanel که از نوع ItemControl نیست و در Text ئه TextBlock هم این نوع binding انجام شد .
هیچکدوم اشتباه نیست، ربطی هم بهم ندارند. اشتباه در اینه که شما بخواهید از روی مثال ها حکم استخراج کنید، کاری که همیشه می کنید و بارها گفتم که استقرا اشتباه ئه. از جزء به کل نمیشه رسید. حکم استقرایی شما اشتباه میشه، نه مثالی که فلان کاربر توضیح داده بود و بر اساسش حکم صادر کرده بودید.
اما سئوال این هست که اگه کالکشن مون از نوع کلاسِ CollectionView نباشه (فرضا از نوع List یا ObservableCollection و ... باشه) ، و همچنین بخوایم عضوی از این کالکشن (فرضا current item از این کالکشن) را به پروپرتیِ یه المنتی جز Selector (مثلا پروپرتیِ یه Button یا مثل کد بالا ، به پروپرتیِ یه TextBlock) متصل کنیم ، در این صورت این current item ئه کالکشن مون ، اولا مقدارش را از کجا میگیره و از کجا مقداردهی میشه . یعنی از کجا متوجه بشیم که current item ئه کالکشن مون ، مقدارش به کدوم عضو از کالکشن مون اشاره میکنه (در صورتی که کالکشن مون CollectionView نباشه و فرضا از نوع List یا ObservableCollection باشه)؟
قضیه برعکس ئه، این Selector ئه که یک آیتمی رو از بین اعضاء منبع داده مورد نظر انتخاب می کنه، وگرنه برای آرایه، مجموعه و ObservableCollection و ... که Selected Item معنی نداره. منبع داده قرار نیست الزما Selected Item ای داشته باشه. CollectionView از این جهت خاص ئه که همچین قابلیتی داره. اگر با منبع داده ای سر و کار دارید که ICollectionView رو نداره، طبعا اون Selector هم بهش اعلام نمی کنه که من فلان آیتم ات رو انتخاب کردم، چون راهی برای ارسال این سیگنال سراغ نداره. پس در چنین حالتی فقط با تغییر در Selector، فرضا تغییر SelectedItem یا SelectionChanged متوجه می شوید، نه اینکه مجموعه منبع سیگنالی دریافت کنه.
بعد این CollectionView (و کلاس های فرزندش) وقتی استفاده میشه که بخوایم به شیِ binding مون از مرتب سازی ، فیلترینگ یا گروه بندی (که دقیقا این دو تای آخر را نمیدونم چیه) ای که در کالکشن مون اتفاق افتاد ، اطلاع بدیم؟
بله، یعنی فقط یک مجموعه داده نیست، مجموعه داده ای است که بشه داخلش یکسری آیتم رو فیلتر کرد، مرتب کرد، آیتم ها رو بالا و پایین کرد، موردی رو انتخاب کرد و ... و همه این تغییرات دو طرفه هم در کنترل و هم در مجموعه داده منعکس بشه، یعنی هم Selector بتونه به CollectionView تغییرات رو اطلاع بده و هم CollectionView بتونه به Selector تغییرات رو اطلاع بده.
میشه بجاش از همون ObservableCollection استفاده کنیم و کالکشن مون را مرتب کنیم و کالکشنِ مرتب شده را بهش مجددا شیِ جدیدی بدیم . (هر چند اصولی شاید نباشه) . درست میگم؟
بحث شدن و نشدن یا اصولی بودن و نبودن نیست، کلاس ها طوری طراحی می شوند که از یک کلاس یا اینترفیس های خاصی برای فعال کردن فلان قابلیت ها استفاده کنند. طبعا اگر اون کلاس ها و اینترفیس ها رو بکار نبرید اون قابلیت ها رو هم نمی توانید بکار ببرید. اینجا فقط بحث اینه که کدوم قابلیت ها رو لازم دارید و کدوم ها رو ندارید. فرضا اگر INotifyPropertyChanged رو بکار نبرید یکسری قابلیت ها رو از دست می دهید، به همین سادگی.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
بله.

نه. به DataContent اون دکمه چیکار دارید؟ بذارید همون مقدار خودکار باشه، اصلا نیازی به اون this.AssociateEventToCommandButton.DataContext = this نیست. وقتی اون کد رو حذفش کردید چه شرایطی دارید؟
شما یک پنجره دارید که همون اول کار برایش یک StudentViewModel رو به عنوان DataContent در نظر گرفته اید. تا اینجا درست.
بعد داخلش یک دکمه دارید که EventToCommand ای داره که قراره Bind کنه روی Path=MouseMoveAssociateEventToCommand
XML:
Command="{Binding Path=MouseMoveAssociateEventToCommand}"
حالا Source برای این Binding چیه؟ بصورت پیشفرض DataContext ئه. در StudentViewModel میگرده دنبال اون MouseMoveAssociateEventToCommand و پیداش نمی کنه و برای همین کار نخواهد کرد. ایراد در چیه؟ در اینکه Source ئه Binding مشخص نشده، نه اینکه View تون با DataContext اشتباهی کار می کنه.

سلامی مجدد
خیلی ممنون استاد .
بله . البته همونطور که گفتید ، Source ئه Binding ، بصورت پیش فرض ، از مقدار DataContext ئه والدش استفاده میکنه که با تغییرش ، اون Source ئه Binding هم تغییر میکنه .

Source اش رو درست تنظیم کنید تا درست بشه :
XML:
Command="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=MouseMoveAssociateEventToCommand}"

این RelativeSource ، یکی از موارد کاربردش زمانی هست که مثل اینجا بخوایم اشاره گر به شی والدش را بدست بیاریم . درسته؟

نباید هم کار کنه، چون Command رو وقتی روی MyMainWindow.MouseMoveAssociateEventToCommand ئه Bind می کنه که مقدار MouseMoveAssociateEventToCommand اش همون مقدار پیشفرض null ئه. Command اش null می مونه.

Binding که موقع اجرای برنامه ، عملیاتش را انجام میداد (و در موقعی که اون رویداد اتفاق میافتاد) .
موقع کمپایل برنامه کاری نمیکرد که نیاز به مقداردهی باشه!

SetBinding هم نباشه BindingOperations.SetBinding که هست.
C#:
            Binding myBinding = new Binding("MouseMoveAssociateEventToCommand");
            myBinding.Source = this;
            BindingOperations.SetBinding(AssociateEventToCommand, EventToCommand.CommandProperty, myBinding);

بله .
خیلی ممنون .


کافیه بهش فکر کنید. MVVM سه تا جزء تفکیک شده تعریف کرده، View و Model و ViewModel.
هیچکدوم هم ناحیه مشترک ندارند، کاملا از هم تفکیک شده اند، در نمودار اش هم مشخص هست.
اگر مشخصات و تعاریف این سه جزء از هم قابل تفکیک نباشند، سه جزء بودن معنی داره؟ طبعا نه.
حالا یک کلاسی رو در پروژه تون تصور کنید که داخلش واسط کاربری و کنترل ها مورد استفاده قرار گرفته و با جزء ViewModel در ارتباط ئه.
این کلاس به جزء ViewModel تعلق داره یا View یا Model؟
با منطق شما هم میتونه به ViewModel تعلق داشته باشه و هم View و احتمالا هم Model؟ چرا؟
چون برای وجود کنترل ها در ViewModel که ایرادی نمی بینید، پس اگر در ViewModel ایرادی نداشته باشه قاعدتا برای وجودش در Model نباید ایرادی بگیرید، البته خیلی هم مهم نیست که وجود اش در Model رو منطقی بدونید یا نه، همون که سر تعلق اش به View و ViewModel ابهام باشه کافیه.
از طرف دیگه اینکه یک جزء از ViewModel بتونه با سایر اجزاء ViewModel در ارتباط باشه مشکلی نداره، بالاخره اجزاء داخلی میتوانند با همدیگه تعامل داشته باشند، همونطور که Button با Grid و Window میتونه رابطه داشته باشه، غیر از اینه؟

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

پس میتونه متعلق به ViewModel باشه که با خودش در ارتباط ئه، مشکلی که نداره؟

نه . نداره .

این کلاس در View هم قطعا میتونه باشه، چون هم با واسط کاربری سر و کار داره و هم ارتباط View با ViewModel منطقی است. این هم که مشکلی نداره؟

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

میشه همچین چیزی که در پروژه شما View و ViewModel محدوده مشترک داشته باشند و همچنان تفکیک سه جزء معماری MVVM صورت گرفته باشه؟

من از این منظر نگاه میکنم که MVVM برای جدا کردنِ View با Model هست .
برای جدا کردنِ View با Model با ViewModel که نیست . درست میگم؟
یعنی نیومد 3 لایه (ی View و Model و ViewModel) را از هم جدا کنه .
بلکه اومد تا لایه ی View با Model را از هم فقط جدا کنه .

بنابراین View یا Model میتونن با ViewModel رابطه داشته باشن .
هر چند منطقی که شما برای ViewModel گفتید که داده را انتقال بده ، تا بشه و تا حد امکان رعایت کرد ، خیلی بهتر و عالی میشه اما اگه جایی نیاز به ارتباط با View یا Model با لایه ی ViewModel داشتن و این کار را انجام بدن ، نقض MVVM ای صورت نمیگیره . همچنان که ViewModel در این پروژه با شیِ Student کار داره یعنی با لایه ی Model ارتباط داره.


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

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

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

هر فرد مستقل انتخاب می کنه، درسته؟ شما در مورد کدوم فرد صحبت می کنید؟ کدوم فرد ئه که رویداد رو بجای Command ترجیح میده؟ مهمه که بدونیم این فرد چی رو ترجیح میده؟

متوجه ام .

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

من از روی مثال ها حکم صادر نکردم .
در هر دو لینک ، خودشون همون حرف را زدن . لینک که دادم . متن شون را هم گذاشتم (و بولد کردم) .

الان مثلا در اون مثالی که طرف زد ، یعنی در کد زیر :

XML:
<DockPanel DataContext="{x:Static Fonts.SystemFontFamilies}">
  <TextBlock DockPanel.Dock="Top"
             Text="{Binding Baseline}" />
  <ListBox ItemsSource="{Binding}"
           IsSynchronizedWithCurrentItem="True" />
</DockPanel>

هر فونت ای که در ListBox انتخاب کنیم ، Baseline ئه فونت انتخاب شده ، در TextBlock نمایش داده میشه .
سئوال اینجاست که انتخاب آیتم که در ListBox اتفاق میافته . اما TextBlock (که همزاد و برادرِ ListBox هست) از کجا متوجه ی این میشه که چه آیتمی در ListBox انتخاب میشه؟
آیا ListBox ، به DockPanel که والدش هست ، انتخابِ آیتمش را خبر میده و مجددا DockPanel به تمام فرزندانش خبر میده؟ روالش این طوره؟
و بعد هم Text ئه TextBlock چون پروپرتیِ Baseline را در Source ئه Binding اش که همون DataContext ئه والد که DockPanel هست (یعنی کالکشنِ Fonts.SystemFontFamilies) ، پیدا نکرد ، میره توی عضوِ انتخاب شده از این کالکشن که از طریقِ DockPanel اون عضوِ انتخاب شده بهش اطلاع داده شد ، میگرده .
آیا روالش اینه؟
اگه این نیست ، پس روال کد بالا ، چجوری کار میکنه و چیه؟


قضیه برعکس ئه، این Selector ئه که یک آیتمی رو از بین اعضاء منبع داده مورد نظر انتخاب می کنه، وگرنه برای آرایه، مجموعه و ObservableCollection و ... که Selected Item معنی نداره. منبع داده قرار نیست الزما Selected Item ای داشته باشه. CollectionView از این جهت خاص ئه که همچین قابلیتی داره. اگر با منبع داده ای سر و کار دارید که ICollectionView رو نداره، طبعا اون Selector هم بهش اعلام نمی کنه که من فلان آیتم ات رو انتخاب کردم، چون راهی برای ارسال این سیگنال سراغ نداره. پس در چنین حالتی فقط با تغییر در Selector، فرضا تغییر SelectedItem یا SelectionChanged متوجه می شوید، نه اینکه مجموعه منبع سیگنالی دریافت کنه.

بله، یعنی فقط یک مجموعه داده نیست، مجموعه داده ای است که بشه داخلش یکسری آیتم رو فیلتر کرد، مرتب کرد، آیتم ها رو بالا و پایین کرد، موردی رو انتخاب کرد و ... و همه این تغییرات دو طرفه هم در کنترل و هم در مجموعه داده منعکس بشه، یعنی هم Selector بتونه به CollectionView تغییرات رو اطلاع بده و هم CollectionView بتونه به Selector تغییرات رو اطلاع بده.

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

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

the_king

مدیرکل انجمن
این RelativeSource ، یکی از موارد کاربردش زمانی هست که مثل اینجا بخوایم اشاره گر به شی والدش را بدست بیاریم . درسته؟
بله، قبلا هم در موردش صحبت کرده بودیم و ازش استفاده شده بود.
Binding که موقع اجرای برنامه ، عملیاتش را انجام میداد (و در موقعی که اون رویداد اتفاق میافتاد) .
موقع کمپایل برنامه کاری نمیکرد که نیاز به مقداردهی باشه!
زمان کامپایل نیست، زمان اجرا است. اصلا در مورد زمان کامپایل حرفی زده نزدم، به زمان کامپایل مربوط نیست، XAML در زمان کامپایل میشه BAML و BAML هم فقط در زمان اجرا است که ظاهر پنجره رو ایجاد می کنه. در زمان کامپایل مقدار دهی Command در پنجره ای که هنوز شیء اش ایجاد نشده که معنی نمیده. داریم در مورد زمان اجرا حرف می زنیم. وقتی پنجره تازه Load میشه هم زمان اجرا است، زمانی که نمایش داده میشه هم زمان اجرا است، زمانی که روی دکمه ای کلیک می کنید هم زمان اجرا است، موقعی که پنجره رو می بندید هم زمان اجرا است، اما در هر کدوم از این زمان ها مشخصه ها و فیلد ها می توانند مقادیر متفاوتی داشته باشند.
من از این منظر نگاه میکنم که MVVM برای جدا کردنِ View با Model هست .
بله، می بینم. برای اینکه اصلا نخوندید ببینید MVVM چیه و در مورد چی حرف می زنه و قواعدش چیه. حتی نمودار معماری اش رو هم ندیدید.
برای همین برای خودتون می بافید و می دوزید. Model و View همینطوری هم از هم جدا بودند، اگر جدا نبودند که دیگه Model و View معنی نداشت.
در معماری Model-View هم از هم جدا هستند، یک Model ئه و یک View که با هم ارتباط دارند.
مثل اینکه در تخم مرغ زرده و سفیده هست، زرده داخل ئه و سفیده دورش و با هم ارتباط دارند و هر کدوم وظایف خودش رو داره. از هم جدا هستند، اگر جدا نبودن که نمی توانستید موقع آشپزی و کیک پزی تفکیک شون کنید و هر کدوم رو در یک ظرفی بریزید. سفیده هم از زرده حفاظت می کنه و هم غذای جنین میشه. زرده هم برای تشکیل جنین ئه. حالا اگر ارتباط بین ایندو رو قطع کنید میشه یک معماری جدید. MVVM رابطه مستقیم بین View و Model رو حذف کرده، نه اینکه از هم جداشون کنه، از اول از هم جدا بودند. این رو فقط زمانی می توانید متوجه بشوید که بخونید ببینید MVVM چیه و در مورد چی داره حرف می زنه، نه اینکه از روی اسمش برای خودتون هدف و قواعد اختراع کنید.
یعنی نیومد 3 لایه (ی View و Model و ViewModel) را از هم جدا کنه .
چرا از خودتون داستان می بافید؟ کجا همچین توضیحی در مورد MVVM داده شده؟ بر اساس کدوم منبع می گوید از هم جدا نشده اند؟ تصویر معماری که کاملا مشخص ئه، از هم جدا نیستند؟ تصویر معماری به کنار، اگر از هم جدا نبودند که ViewModel یا در Model بود یا در View و دیگه معماری سه جزئی نبود.
There are three core components in the MVVM pattern: the model, the view, and the view model. Each serves a distinct purpose.
distinct و purpose رو در دیکشنری جستجو کنید و ببینید distinct purpose یعنی چی.
بلکه اومد تا لایه ی View با Model را از هم فقط جدا کنه.
اشتباه ئه. از اول هم جدا بود. در Model-View هم Model یک جزء جدا بود و View یک جزء جدا دیگه.
هر چند منطقی که شما برای ViewModel گفتید که داده را انتقال بده ، تا بشه و تا حد امکان رعایت کرد ، خیلی بهتر و عالی میشه اما اگه جایی نیاز به ارتباط با View یا Model با لایه ی ViewModel داشتن و این کار را انجام بدن ، نقض MVVM ای صورت نمیگیره.
بشه و تا حد امکان؟ ViewModel کارش همینه. یعنی چی که تا حد امکان؟ اینها رو کجا گفتن؟ از و به ViewModel اگر داده ای منتقل نشه که دیگه امکان رسیدن داده از View به Model یا برعکس نیست. واسطه باید داده رد و بدل کنه تا داده منتقل بشه. ارتباط View یا Model با لایه ی ViewModel هم در کل متن های قبلی بوده، بدیهیات رو بعد از یک عالمه مطلب جای پاسخ یک موضوع دیگه نگید. برگردید و مطالب قبلی رو از نو بخونید و ببینید این حرفی که می زنید اصلا ربطی به موضوع بحث انتقال کنترل های واسط کاربری به ViewModel داره یا نه؟ جایی متنی نوشته بودم که بگه "اگر جایی نیاز به ارتباط با View یا Model با لایه ی ViewModel داشتن و این کار را انجام بدن ، نقض MVVM ای صورت میگیره؟"
 

the_king

مدیرکل انجمن
من از روی مثال ها حکم صادر نکردم .
برگردید به اون لینک در پست 720 ای که مورد اول مقایسه تون بود. بعد بگید در جواب سوال اون کاربر کجا حکمی نوشته شده بود و یا ایراد پاسخی که برای مثال کاربر داده شده چیه تا بگم چطور حکم صادر کرده اید :
هر فونت ای که در ListBox انتخاب کنیم ، Baseline ئه فونت انتخاب شده ، در TextBlock نمایش داده میشه .
سئوال اینجاست که انتخاب آیتم که در ListBox اتفاق میافته . اما TextBlock (که همزاد و برادرِ ListBox هست) از کجا متوجه ی این میشه که چه آیتمی در ListBox انتخاب میشه؟
به اون DataContext توجه کنید، هم TextBlock و هم ListBox دارند با Binding با اون DataContext کار می کنند، هیچ کدوم برای خودشون SystemFontFamilies مستقل ندارند که بگیم منبع شون سوا است و نمی توانند به همدیگه اطلاعی بدهند. منبع شون یک DataContext یکسان ئه و هر دوشون هم با Binding باهاش ارتباط دارند. Binding چه خاصیتی داره؟ اینکه میتونه متوجه تغییر بشه و به منبع یا هدف یا هر دو اطلاع بده که تغییری رخ داده. این قابلیت Binding ئه، ListBox موقعی که آیتمی رو در اون منبع داده مشخص کرد میتونه به Binding هر مورد دیگری که همون منبع رو بکار میبره اطلاع بده که یه چیزی تغییر کرده، حالا اگر تغییر تاثیر بذاره Binding اش منعکس می کنه.
آیا ListBox ، به DockPanel که والدش هست ، انتخابِ آیتمش را خبر میده و مجددا DockPanel به تمام فرزندانش خبر میده؟ روالش این طوره؟
نه دقیقا، DataContext اش در اون DockPanel ئه اما در واقع نه، به خود DockPanel اطلاع نمیده به Binding هایی که به اون منبع داده مرتبط هستند اطلاع میده. سلسله مراتبی ئه دیگه، مثل همون Routed Events در رخداد های WPF. اگر توضیحات مفصل رو بخواهید در همون مباحث Binding سایت مایکروسافت مطلب زیاد ئه.
و بعد هم Text ئه TextBlock چون پروپرتیِ Baseline را در Source ئه Binding اش که همون DataContext ئه والد که DockPanel هست (یعنی کالکشنِ Fonts.SystemFontFamilies) ، پیدا نکرد ، میره توی عضوِ انتخاب شده از این کالکشن که از طریقِ DockPanel اون عضوِ انتخاب شده بهش اطلاع داده شد ، میگرده .
کاری به خود DockPanel نداره، با DataContext اش و با Binding ها کار داره. رخداد ها اول در ListBox منجر به تغییر میشه و Binding اش می فهمه که تغییر رخ داده و بعد دیگه از اون به بعد نشر این تغییر به عهده بقیه Binding هایی است که منتظر دریافت سیگنال هستند.
 

SajjadKhati

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

خیلی ممنون استاد .
بله گفته بودید .

زمان کامپایل نیست، زمان اجرا است. اصلا در مورد زمان کامپایل حرفی زده نزدم، به زمان کامپایل مربوط نیست، XAML در زمان کامپایل میشه BAML و BAML هم فقط در زمان اجرا است که ظاهر پنجره رو ایجاد می کنه. در زمان کامپایل مقدار دهی Command در پنجره ای که هنوز شیء اش ایجاد نشده که معنی نمیده. داریم در مورد زمان اجرا حرف می زنیم. وقتی پنجره تازه Load میشه هم زمان اجرا است، زمانی که نمایش داده میشه هم زمان اجرا است، زمانی که روی دکمه ای کلیک می کنید هم زمان اجرا است، موقعی که پنجره رو می بندید هم زمان اجرا است، اما در هر کدوم از این زمان ها مشخصه ها و فیلد ها می توانند مقادیر متفاوتی داشته باشند.

بله . ممنون

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

چرا از خودتون داستان می بافید؟ کجا همچین توضیحی در مورد MVVM داده شده؟ بر اساس کدوم منبع می گوید از هم جدا نشده اند؟ تصویر معماری که کاملا مشخص ئه، از هم جدا نیستند؟ تصویر معماری به کنار، اگر از هم جدا نبودند که ViewModel یا در Model بود یا در View و دیگه معماری سه جزئی نبود.

distinct و purpose رو در دیکشنری جستجو کنید و ببینید distinct purpose یعنی چی.

اشتباه ئه. از اول هم جدا بود. در Model-View هم Model یک جزء جدا بود و View یک جزء جدا دیگه.

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

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

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



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

به اون DataContext توجه کنید، هم TextBlock و هم ListBox دارند با Binding با اون DataContext کار می کنند، هیچ کدوم برای خودشون SystemFontFamilies مستقل ندارند که بگیم منبع شون سوا است و نمی توانند به همدیگه اطلاعی بدهند. منبع شون یک DataContext یکسان ئه و هر دوشون هم با Binding باهاش ارتباط دارند. Binding چه خاصیتی داره؟ اینکه میتونه متوجه تغییر بشه و به منبع یا هدف یا هر دو اطلاع بده که تغییری رخ داده.

این قابلیت Binding ئه، ListBox موقعی که آیتمی رو در اون منبع داده مشخص کرد میتونه به Binding هر مورد دیگری که همون منبع رو بکار میبره اطلاع بده که یه چیزی تغییر کرده، حالا اگر تغییر تاثیر بذاره Binding اش منعکس می کنه.

نه دقیقا، DataContext اش در اون DockPanel ئه اما در واقع نه، به خود DockPanel اطلاع نمیده به Binding هایی که به اون منبع داده مرتبط هستند اطلاع میده. سلسله مراتبی ئه دیگه، مثل همون Routed Events در رخداد های WPF. اگر توضیحات مفصل رو بخواهید در همون مباحث Binding سایت مایکروسافت مطلب زیاد ئه.

کاری به خود DockPanel نداره، با DataContext اش و با Binding ها کار داره. رخداد ها اول در ListBox منجر به تغییر میشه و Binding اش می فهمه که تغییر رخ داده و بعد دیگه از اون به بعد نشر این تغییر به عهده بقیه Binding هایی است که منتظر دریافت سیگنال هستند.

خیلی ممنون .
بله . اما برای اطلاع و تغییر مقدار دادن در این مثال ، باید Binding مون دو طرفه باشه دیگه . درست میگم؟
در اینجا مگه دو طرفه هست؟

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


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

the_king

مدیرکل انجمن
الان یه سئوال در این رابطه اینکه ViewModel مون که با Model مون ارتباط داره . درسته؟ همون شیِ Student ای که توی StudentViewModel مون بود (شیِ Student که مربوط به Model مون هست دیگه).
آیا ارتباط برقرار کردنِ این دو با هم (Model با ViewModel)، باعث نقضِ MVVM شد؟
جوابش مشخص هست که نه هست . درسته؟
پس چطور ارتباط برقرار کردنِ View با ViewModel مون (و ارسال شی ای از کنترل و المنت ها که به View مربوطه) ، باعث نقضِ MVVM میشه؟
در اونجا که نشد ، در اینجا هم طبعا نباید نقض بشه دیگه .
نمیدونم تونستم منظورم را برسونم یا نه .
توضیح دادم که نقض MVVM بخاطر چیه، بخاطر این نیست که View با ViewModel ارتباط برقرار کرده. بخاطر ارسال شیء کنترل و المنت ها به ViewModel ئه، نه داده. جای اجزاء واسط کاربری کجا است؟ داخل View، فقط داخل View. نه Model و نه ViewModel نباید کاری با واسط کاربری داشته باشند. دائم دارم این مساله رو تکرار می کنم و اصلا در پاسخ تون اشاره بهش نمی کنید. اجزاء واسط کاربری رو که منتقل کردید داخل ViewModel یعنی تفکیک وظایف View و ViewModel رو بهم زدید، ViewModel ای ساخته اید که هم به واسط کاربری می پردازه (مشابه View) و هم بین View و Model واسطه شده، این دیگه معماری MVVM نیست.
بله . اما برای اطلاع و تغییر مقدار دادن در این مثال ، باید Binding مون دو طرفه باشه دیگه . درست میگم؟
نه. در ضمن برای فهمیدن جواب این سوال نیازی نیست بپرسید، می توانید با مقدار دهی صریح Mode ئه Binding تاثیر اش رو در اجرا ببینید و حتی ببینید کجاها Binding دو طرفه معنی داره.
در اینجا مگه دو طرفه هست؟
نه.
الان شما میگید که یه Binding ، میتونه به همه ی اشیاء Binding ئه دیگه ای که Source (یا همون DataContext) ئه مشترک دارن ، اطلاع از تغییر مقدارش را بده؟
بله.
در صحبت ، این درکش آسونه ولی نمیدونم از لحاظ کدنویسی چجوری امکان پذیر و شدنی میشه؟
اگر بخواهید می توانید کدشون رو بررسی کنید.
میتونم درخواست کنم که یه مثالِ کدنویسی از این قضیه چجوری میشه و Binding ها در داخل شون ، چجوری این اطلاع رسانی به Source ئه مشترک را انجام میدن؟
یا لینکی یا مطلبی از این قضیه؟
مستندات قراره بگن چطور ازشون استفاده بشه، نه اینکه کد پشت صحنه شون چطور کار می کنند، چون قاعدتا برنامه نویس نیازی به جواب سوال شما نداره. بهترین راه، تحلیل کد شونه، اما در حالت کلی امکانات کلاس Binding رو ببینید، ببینید برای اینکه خبر بده و خبر بگیره چه امکاناتی داره، چه اطلاعاتی رو در خودش نگه میداره که برای اطلاع رسانی بدرد میخوره. مشخصه هایش رو ببینید، رخداد هاش رو ببینید، فیلد های مرتبط با رخداد هایش رو ببینید، اون متد هایش که برای اطلاع رسانی با handler ثبت نام می کنند رو ببینید و ...
 

SajjadKhati

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

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

اینها را قبلا گفتید . میدونم .
الان شما میگید که کار کردن با کنترل ها ، فقط وظیفه ی View هست و نباید شی ای از کنترل ها به ViewModel ارسال بشه . بلکه نهایتا باید داده (شون) ارسال بشه .
بنابراین اگه کنترلی از View به ViewModel ارسال بشه ، MVVM را نقض کرده . درسته؟ (تا اینجا حرف شماست) .

بنابراین به طبع ، باید حالت برعکسش هم وجود داشته باشه . یعنی مواردی باشن که اگه در ایجادِ ارتباط برقرار کردن بین لایه ی ViewModel با Model انجام بشه و شی ای بین شون ارسال بشه، باعث نقضِ MVVM بشه . درست میگم؟
(چون مواردی وجود داره که اگه در ارتباط برقرار کردن بین ViewModel با View انجام بدیم ، یعنی اگه شیِ کنترل را از View به ViewModel ارسال کنیم ، باعث نقض MVVM شدیم ، پس باید در ارتباط با ViewModel با Model هم همچین مواردی وجود داشته باشه) .
اگه درست میگم پس این موارد چه چیزهایی هستن (در ارتباط برقرار کردن بین ViewModel با Model که اگه انجام بدیم و شی ای را بین شون ارسال کنیم ، باعث نقض MVVM میشیم)؟
اگه همچین مواردی در ارتباط برقرار کردن بین ViewModel با Model وجود نداره که باعث بشه MVVM نقض بشه ، پس چطور در ارتباط با View و ViewModel وجود داره؟


نه. در ضمن برای فهمیدن جواب این سوال نیازی نیست بپرسید، می توانید با مقدار دهی صریح Mode ئه Binding تاثیر اش رو در اجرا ببینید و حتی ببینید کجاها Binding دو طرفه معنی داره.

نه.

بله.

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

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

خیلی ممنون .
من بیشتر میخوام منبعی برای این قضیه پیدا کنم .
یعنی شما گفتید که یه Binding ، میتونه به همه ی اشیاء Binding ئه دیگه ای که Source (یا همون DataContext) ئه مشترک دارن ، اطلاع از تغییر مقدارش را بده ؛ منبع یا مقاله ای در این باره میخوام .
منظورم اینه که شما از کجا میگید؟ در مقاله یا جایی خوندید یا اینکه مثلا در چند جا ، چیزهای متفاوتی درباره ی Binding خوندین که بعد جمع بندی کردین و به این نتیجه رسیدین یا چیز دیگه ای هست؟
مثلا اگه جایی نوشته ، میخوام در این باره بیشتر بخونم که چطور و با چه روال و روندی این کار را انجام میده .

تشکر استاد.
 

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

بالا