SajjadKhati
کاربر فعال <A href="http://forum.majidonline.com/f
سلامی مجدد استاد
خیلی ممنون از جواب پست قبلی تون .
استاد ، میگم که پست های 949 تا 963 را مرور کردم .
درباره ی مشکل Binding ای بود که توسط Converter بوجود میومد و در جریانش ، در پست 949 ، پروژه ی کوچیک SettingBinding را ایجاد کردم و شما هم در پست 952 ، پروژه ی BindingSample را دادید .
هر چند خلاصه ی صحبت های شما را در پست های 959 و پست 961 گفتم ، اما همونطور که اشاره کرده بودید به همون پست ها ، اندکی شاید اشکالاتی داشت .
حالا توی این پست میخوام اون مطالب را تصحیح کنم و البته به همراه یک نکته و این مطالبی که میگم را بی زحمت چک کنید ببینید درسته ؟ :
==========
اول ، یک نکته اینکه من در ILSpy و اینها که چک میکردم ، کلاس های ItemsControl و فرزندان شون ، از رویداد CollectionChanged (ئه اینترفیسِ INotifyCollectionChanged که توسط ObservableCollection<T> پیاده سازی شد) استفاده نمیکنن .
و متدی را به این رویداد CollectionChanged ، متصل نمیکنن .
حداقل من چیزی پیدا نکردم .
=========
در Binding ، فقط هر بار که شیِ اون پروپرتی عوض بشه ، شیِ بایندینگ ، به Binding Target Property اش اطلاع میده . در واقع شیِ Binding ، اشاره گر را برای Binding Target Property ، همون اشاره گرِ شی ای که Binding Source Property بهش اشاره میکنه ، در نظر میگیره (یا فرضا اگه اون شی ، استراکچر هست ، مقدارش را به همون تغییر میده) .
یعنی فرضا اگه پروپرتیِ HasGoodState را به عنوان Binding Source Property استفاده میکنیم ، اگه مقدارش تغییر کنه ، به Binding Target Property اش اطلاع و همون اشاره گر را براش در نظر میگیره .
برای کالکشن ها ، باز هم اگه فقط شیِ کالکشن عوض بشه (نه اینکه آیتمی بهش اضافه یا حذف بشه) ، شیِ بایندینگ ، به Binding Target Property اش بصورت اتوماتیک اطلاع میده . و مثل حالت قبلی ، به همون اشاره گری که Binding Source Property داره به شیِ کالکشن اشاره میکنه ، همون اشاره گر را به عنوان اشاره گر برای شیِ Binding Target Property در نظر میگیره .
یعنی اگه پروپرتیِ Drives را که به عنوان Binding Source Property استفاده میکنیم و به پروپرتیِ DrivesForView (به عنوان Binding Target Property) ، بایندینگ میکنیم ، در اینجا فقط اگه مقدار Drives تغییر کنه (نه اینکه عضوی را بهش اضافه و حذف کنیم) ، در این صورت فقط اتوماتیک به پروپرتیِ DrivesForView اطلاع و مقدارش را به همون اشاره گر تغییر میده .
اضافه شدن یا حذف شدن اعضا از یه کالکشن ، به Binding هیچ ارتباطی نداره و در این صورت ، Binding هیچ اطلاعی به Target Property اش نمیده .
Binding ، فقط در صورتی که مقدار پروپرتیِ Source Property اگه تغییر کنه ، اون مقدار یا اشاره گرِ اون مقدار را برای Target Property در نظر میگیره و تغییرش میده . (نه اینکه فرضا اگه Source Property مون ، یه کالکشن بود ، اعضای این کالکشن اگه تغییر کرد ، این کار را کنه یا فرضا اگه مقدار پروپرتی هایی که داخلِ Source Property مون هستن ، تغییر کرد ، این کار را کنه) .
همونطور که اشاره شد ، در واقع ، در این صورت (وقتی Binding میکنیم) ، هر دوی Binding Source Property و هم Binding Target Property ، از همون شی استفاده میکنن (مثل اینکه یک شی را توی یک متغییر بریزیم و بعد همون متغییر را توی متغییر دیگه ای بریزیم) .
بنابراین وقتی به یه پروپرتیِ (به عنوان Binding Target Property) ، یه کالکشن را بهش Binding کنیم ، فقط کافیه که یکبار کالکشنِ سورس مون ، مقداردهی بشه ، همون کالکشن ، به عنوان کالکشن Target مون در نظر گرفته میشه . پس دیگه مهم هم نیست که دیگه با هر بار اضافه شدن آیتم به کالکشنِ سورس مون ، خبری به Binding یا Target داده بشه .
حالا به کالکشن Source مون هم که هر تغییری بدیم و اعضایی را حذف یا اضافه کنیم ، یعنی به همون کالکشنِ Target مون همون تغییرات را داده بودیم (چون شیِ کالکشنِ هر دو پروپرتی ، یکی هستن) .
یعنی شکل زیر ، بیانگر توصیفات بالا هست :
==================
حالا مشکل این پروژه ام (پروژه ی BindingSetting در پست 949) اینه که برای این Binding ، از Converter بصورتی استفاده کردم که شیِ جدیدی در Converter برای Binding ام ساختم .
Target Property هم اگه از Converter ای استفاده کنیم ، همیشه ، شی ای که Converter در اختیارش قرار میده را استفاده میکنه و به این شی ، Binding انجام میده (چه این شی ای که Converter در اختیارش قرار میده ، همون شی ای باشه که Source Property بهش اشاره میکنه ، یا اینکه شی دیگه ای باشه) (یعنی در این صورت ، Target Property مون مستقیما کاری به شی Source Property نداره و بهش Binding نمیشه) .
در این پروژه ، پروپرتی Drives که از نوع InternalHard_DriveCollection و این نوع هم همون ObservableCollection<Drive> هست ، به عنوان Source Property مون هست .
پروپرتی DrivesForView هم که از نوع ObservableCollection<DriveForView> هست ، به عنوان Target Property مون هست .
در این Binding هم از Converter استفاده کردیم .
وقتی Drives را به DrivesForView مون Binding کردیم ، زمانی که به پروپرتیِ Drives مقدار (شی ای از InternalHard_DriveCollection) دادیم ، این شی توسط شیِ Binding ، (به عنوان پارامتر value ، به متدِ) Convert مون اطلاع میده .
در این لحظه ، متد Convert ، از این شی ای که Drives بهش اشاره میکنه ، هیچ استفاده ای نمیکنه و یک شیِ دیگه ای (از نوع ObservableCollection<DriveForView>) میسازه و Target Property مون دیگه از این شی استفاده میکنه .
همونطور هم که قبلا اشاره شد ، اگه از Converter استفاده کنیم ، Target Property مون (در اینجا DrivesForView) ،در واقع به شی ای که Converter مون به عنوان خروجی میده ، Binding میشه (حالا Converter مون میخواد چه همون شی ای که در Source Property بهش اشاره میشه را تحویل بده یا یه شی دیگه را تحویل بده) (یعنی در این صورت ، Target Property مون مستقیما کاری به شی Source Property نداره) .
و چون شی ای که در متد Convert تحویل میده ، شی ای متفاوت از شی ای هست که Source Property مون بهش اشاره میکنه ، پس هر وقت اگه به اعضای Source Property مون ، عضوی اضافه یا کم بشه ، شی ای که در خروجیِ Converter ازش استفاده میکنیم (شیِ از نوع ObservableCollection<DriveForView>) ، مطلع نمیشه تا به اعضای خودش هم چیزی اضافه یا حذف یا ویرایش کنه (چون وظیفه ی Binding همونطور که گفته شد ، فقط وقتی هست که مقدار پروپرتی تغییر کنه ، نه اینکه اعضای کالکشن تغییر کنه و ...) و چون این دو شی (شی در خروجیِ Convert و شی Source Property) یک شی هم نیستن (و دو شی مجزا هستن) ، با اضافه شدن اعضا به شی Source Property ، مشخص و بدیهی هست که شی دیگری هم تغییری نمیکنه .
راه حل هم اینه که در Converter ، هندلری به رویداد CollectionChanged ئه شیِ Source Property مون متصل کنیم و طبق حذف و اضافه شدنِ اعضا به این شی ، اون عضو را در شیِ خروجیِ Converter هم حذف یا اضافه کنیم .
درسته؟
ببخشید زیاد شد .
تشکر استاد
خیلی ممنون از جواب پست قبلی تون .
استاد ، میگم که پست های 949 تا 963 را مرور کردم .
درباره ی مشکل Binding ای بود که توسط Converter بوجود میومد و در جریانش ، در پست 949 ، پروژه ی کوچیک SettingBinding را ایجاد کردم و شما هم در پست 952 ، پروژه ی BindingSample را دادید .
هر چند خلاصه ی صحبت های شما را در پست های 959 و پست 961 گفتم ، اما همونطور که اشاره کرده بودید به همون پست ها ، اندکی شاید اشکالاتی داشت .
حالا توی این پست میخوام اون مطالب را تصحیح کنم و البته به همراه یک نکته و این مطالبی که میگم را بی زحمت چک کنید ببینید درسته ؟ :
==========
اول ، یک نکته اینکه من در ILSpy و اینها که چک میکردم ، کلاس های ItemsControl و فرزندان شون ، از رویداد CollectionChanged (ئه اینترفیسِ INotifyCollectionChanged که توسط ObservableCollection<T> پیاده سازی شد) استفاده نمیکنن .
و متدی را به این رویداد CollectionChanged ، متصل نمیکنن .
حداقل من چیزی پیدا نکردم .
=========
در Binding ، فقط هر بار که شیِ اون پروپرتی عوض بشه ، شیِ بایندینگ ، به Binding Target Property اش اطلاع میده . در واقع شیِ Binding ، اشاره گر را برای Binding Target Property ، همون اشاره گرِ شی ای که Binding Source Property بهش اشاره میکنه ، در نظر میگیره (یا فرضا اگه اون شی ، استراکچر هست ، مقدارش را به همون تغییر میده) .
یعنی فرضا اگه پروپرتیِ HasGoodState را به عنوان Binding Source Property استفاده میکنیم ، اگه مقدارش تغییر کنه ، به Binding Target Property اش اطلاع و همون اشاره گر را براش در نظر میگیره .
برای کالکشن ها ، باز هم اگه فقط شیِ کالکشن عوض بشه (نه اینکه آیتمی بهش اضافه یا حذف بشه) ، شیِ بایندینگ ، به Binding Target Property اش بصورت اتوماتیک اطلاع میده . و مثل حالت قبلی ، به همون اشاره گری که Binding Source Property داره به شیِ کالکشن اشاره میکنه ، همون اشاره گر را به عنوان اشاره گر برای شیِ Binding Target Property در نظر میگیره .
یعنی اگه پروپرتیِ Drives را که به عنوان Binding Source Property استفاده میکنیم و به پروپرتیِ DrivesForView (به عنوان Binding Target Property) ، بایندینگ میکنیم ، در اینجا فقط اگه مقدار Drives تغییر کنه (نه اینکه عضوی را بهش اضافه و حذف کنیم) ، در این صورت فقط اتوماتیک به پروپرتیِ DrivesForView اطلاع و مقدارش را به همون اشاره گر تغییر میده .
اضافه شدن یا حذف شدن اعضا از یه کالکشن ، به Binding هیچ ارتباطی نداره و در این صورت ، Binding هیچ اطلاعی به Target Property اش نمیده .
Binding ، فقط در صورتی که مقدار پروپرتیِ Source Property اگه تغییر کنه ، اون مقدار یا اشاره گرِ اون مقدار را برای Target Property در نظر میگیره و تغییرش میده . (نه اینکه فرضا اگه Source Property مون ، یه کالکشن بود ، اعضای این کالکشن اگه تغییر کرد ، این کار را کنه یا فرضا اگه مقدار پروپرتی هایی که داخلِ Source Property مون هستن ، تغییر کرد ، این کار را کنه) .
همونطور که اشاره شد ، در واقع ، در این صورت (وقتی Binding میکنیم) ، هر دوی Binding Source Property و هم Binding Target Property ، از همون شی استفاده میکنن (مثل اینکه یک شی را توی یک متغییر بریزیم و بعد همون متغییر را توی متغییر دیگه ای بریزیم) .
بنابراین وقتی به یه پروپرتیِ (به عنوان Binding Target Property) ، یه کالکشن را بهش Binding کنیم ، فقط کافیه که یکبار کالکشنِ سورس مون ، مقداردهی بشه ، همون کالکشن ، به عنوان کالکشن Target مون در نظر گرفته میشه . پس دیگه مهم هم نیست که دیگه با هر بار اضافه شدن آیتم به کالکشنِ سورس مون ، خبری به Binding یا Target داده بشه .
حالا به کالکشن Source مون هم که هر تغییری بدیم و اعضایی را حذف یا اضافه کنیم ، یعنی به همون کالکشنِ Target مون همون تغییرات را داده بودیم (چون شیِ کالکشنِ هر دو پروپرتی ، یکی هستن) .
یعنی شکل زیر ، بیانگر توصیفات بالا هست :
==================
حالا مشکل این پروژه ام (پروژه ی BindingSetting در پست 949) اینه که برای این Binding ، از Converter بصورتی استفاده کردم که شیِ جدیدی در Converter برای Binding ام ساختم .
Target Property هم اگه از Converter ای استفاده کنیم ، همیشه ، شی ای که Converter در اختیارش قرار میده را استفاده میکنه و به این شی ، Binding انجام میده (چه این شی ای که Converter در اختیارش قرار میده ، همون شی ای باشه که Source Property بهش اشاره میکنه ، یا اینکه شی دیگه ای باشه) (یعنی در این صورت ، Target Property مون مستقیما کاری به شی Source Property نداره و بهش Binding نمیشه) .
در این پروژه ، پروپرتی Drives که از نوع InternalHard_DriveCollection و این نوع هم همون ObservableCollection<Drive> هست ، به عنوان Source Property مون هست .
پروپرتی DrivesForView هم که از نوع ObservableCollection<DriveForView> هست ، به عنوان Target Property مون هست .
در این Binding هم از Converter استفاده کردیم .
وقتی Drives را به DrivesForView مون Binding کردیم ، زمانی که به پروپرتیِ Drives مقدار (شی ای از InternalHard_DriveCollection) دادیم ، این شی توسط شیِ Binding ، (به عنوان پارامتر value ، به متدِ) Convert مون اطلاع میده .
در این لحظه ، متد Convert ، از این شی ای که Drives بهش اشاره میکنه ، هیچ استفاده ای نمیکنه و یک شیِ دیگه ای (از نوع ObservableCollection<DriveForView>) میسازه و Target Property مون دیگه از این شی استفاده میکنه .
همونطور هم که قبلا اشاره شد ، اگه از Converter استفاده کنیم ، Target Property مون (در اینجا DrivesForView) ،در واقع به شی ای که Converter مون به عنوان خروجی میده ، Binding میشه (حالا Converter مون میخواد چه همون شی ای که در Source Property بهش اشاره میشه را تحویل بده یا یه شی دیگه را تحویل بده) (یعنی در این صورت ، Target Property مون مستقیما کاری به شی Source Property نداره) .
و چون شی ای که در متد Convert تحویل میده ، شی ای متفاوت از شی ای هست که Source Property مون بهش اشاره میکنه ، پس هر وقت اگه به اعضای Source Property مون ، عضوی اضافه یا کم بشه ، شی ای که در خروجیِ Converter ازش استفاده میکنیم (شیِ از نوع ObservableCollection<DriveForView>) ، مطلع نمیشه تا به اعضای خودش هم چیزی اضافه یا حذف یا ویرایش کنه (چون وظیفه ی Binding همونطور که گفته شد ، فقط وقتی هست که مقدار پروپرتی تغییر کنه ، نه اینکه اعضای کالکشن تغییر کنه و ...) و چون این دو شی (شی در خروجیِ Convert و شی Source Property) یک شی هم نیستن (و دو شی مجزا هستن) ، با اضافه شدن اعضا به شی Source Property ، مشخص و بدیهی هست که شی دیگری هم تغییری نمیکنه .
راه حل هم اینه که در Converter ، هندلری به رویداد CollectionChanged ئه شیِ Source Property مون متصل کنیم و طبق حذف و اضافه شدنِ اعضا به این شی ، اون عضو را در شیِ خروجیِ Converter هم حذف یا اضافه کنیم .
درسته؟
ببخشید زیاد شد .
تشکر استاد