دوم و از همه مهمتر اینکه ، هر CollectionView ، یه پروپرتی ای بنام CollectionView.CurrentItem داره که میشه باهاش آیتم خاصی از کالکشن مون را انتخاب کنیم :
Gets the current item in the view.
docs.microsoft.com
The current item of the collection is bound to automatically if the target of a binding is a singleton value. If the target is an ItemsControl, the current item is synchronized with the selected item.
A collection view also maintains a pointer to the current item in the collection.
Because WPF binds to a collection only by using a view (either a view you specify, or the collection's default view), all bindings to collections have a current item pointer.
اما اگه مقدار این پروپرتی را خودمون تنظیم نکنیم (با متد SetCurrent میشه مقدار این پروپرتی را تنظیم کرد) ، یعنی اگه wpf این پروپرتی بصورت اتوماتیک تنظیم کنه (مثلا زمانی که از Default CollectionView استفاده میشه) ، اگه (پروپرتیِ) Target Binding مون از نوع کنترلِ ItemsControl باشه (مثلا پروپرتیِ ItemsControl.ItemsSource باشه)
و همچنین اگه Binding Source مون هم یه کالکشن باشه ، مقدار CurrentItem (ئه CollectionView) مون
برابر با آیتم انتخاب شده در کنترلِ ItemsControl میشه .
ببینید اینی که میگم ، درسته؟ :
اگه (پروپرتیِ) Target Binding مون ، یه پروپرتیِ تک مقداره باشه و از نوعِ کالکشن نباشه (مثل پروپرتیِ TextBlock.Text در مثال پست 742) ، پروپرتیِ CurrentItem ، به اون پروپرتی (TextBlock.Text) مون Binding میشه .
(سه تا مونده به آخری در نقلِ قولِ پستِ بالا ، منظورش اینی هست که گفتم) ؟
اگه هست ، پس در جای دیگه میگه که :
When binding to a view, the slash ("/") character in a Path value designates the current item of the view.
که یعنی
برای Binding کردن به پروپرتیِ CollectionView.CurrentItem ، باید در مقدارِ پروپرتیِ Path ئه Binding مون ، کاراکترِ اسلش "/" را بذاریم . مثل مثال زیر :
کد:
<Button Content="{Binding Path=/}" />
اما اگه این طور نیست ، من هنوز سناریوی کد پست 742 یا کد در چند پاراگراف زیر را متوجه نشدم .
--------------------------
در واقع ، اگه یه پروپرتیِ Target Binding ای را (که از نوعِ کالکشن نباشه مثل پروپرتیِ TextBlock.Text در اوم مثال) Binding کنیم که Binding Source اش ، یه شیِ کالکشن باشه (و میدونیم هم که هر کالکشن ای که Binding میشه ، حداقل یه شیِ CollectionView ئه مربوط به خودش را داره) ، در واقع Path ئه اون Binding ، اتوماتیک به پروپرتیِ CollectionView.CurrentItem متصل و Binding میشه . حتی بدون کاراکتر اسلش (که بدون کاراکتر اسلش ، غلط هست اما بدون این کاراکتر ، من سناریوی کد زیر را متوجه نمیشم) .
درست میگم؟
-------------------------
در واقع در مثال زیر ، سناریوی خودم را میگم (که احتمالا چون برای Binding کردن به پروپرتیِ Baseline با Text ئه TextBlock ، کاراکتر اسلش را نذاشت ، سناریو ام غلط هست) و شما درستی اش را بررسی کنید . اگه اشتباه میکنم ، پس سناریو اش چجوری میشه؟ :
XML:
<DockPanel DataContext="{x:Static Fonts.SystemFontFamilies}">
<TextBlock DockPanel.Dock="Top"
Text="{Binding Baseline}" />
<ListBox ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="True" />
</DockPanel>
مقدار DataContext یا همون Source ئه همه ی کنترل های فرزندش که Binding انجام میده ، از نوع کالکشنی از FontFamily که همون Fonts.SystemFontFamilies باشه ، هست .
خودِ کالکشنِ Fonts.SystemFontFamilies که چون به عنوان Binding Source داره استفاده میشه و ما هم CollectionView ای براش تعریف نکردیم ، پس wpf برای این کالکشنِ Fonts.SystemFontFamilies مون ، یه شیِ پیش فرضِ CollectionView تعریف میکنه .
در واقع پروپرتی های ItemsSource ئه ListBox و Text ئه TextBlock مون در کد بالا ، مستقیما به کالکشنِ Fonts.SystemFontFamilies مون Binding نمیشن . بلکه هر دوی این پروپرتی ها به شیِ پیش فرضِ CollectionView مون (که در کد بالا نیست و wpf بصورت اتوماتیک ساخت) ، Binding میشن و CollectionView ئه پیش فرض مون هم به کالکشنِ Fonts.SystemFontFamilies مون Binding میشه .
چون مقدارِ Path در Binding ئه پروپرتیِ ItemsSource.ListBox مشخص نشد ، پس کل کالکشنِ Fonts.SystemFontFamilies (در واقع شیِ پیش فرضِ CollectionView) به این پروپرتی Binding میشه که بدیهی هست .
اما نکته ی مهم اینجاست که چون پروپرتیِ Text ئه TextBlock ، از نوعی نیست که کالکشن ای را قبول کنه ، پس Path ئه Binding در پروپرتیِ Text ئه TextBlock ، به پروپرتیِ CollectionView.CurrentItem (در شیِ پیش فرضِ CollectionView که اتوماتیک توسط wpf ساخته میشه) ، Binding میشه .
از طرفی هم که هر تغییر انتخابِ آیتم هادرونِ کنترلِ ListBox (تغییر انتخاب آیتم ها توسط کاربر نهایی یا برنامه نویس برنامه توسط کدها) ، باعث میشه که مقدارِ پروپرتیِ CollectionView.CurrentItem ای که بهش Binding شده بود ، تغییر کنه و از طرفی هم پروپرتیِ Text ئه TextBlock هم از همین شی از CollectionView استفاده میکنه و به پروپرتیِ CurrentItem از همین شیِ CollectionView مون Binding شده بود ، باعث میشه که پروپرتیِ Text ئه TextBlock هم تغییر کنه .
درست میگم؟
اما جالب اینکه من قبل از پروپرتیِ Baseline ، یه اسلش اضافه میکنم ، یعنی کد زیر :
XML:
<TextBlock DockPanel.Dock="Top"
Text="{Binding /Baseline}" />
که در پنلِ Error List ، ارور زیر را میده :
Type 'ICollection`1' is not a collection.
اما با کمال تعجب ، هم برنامه به درستی اجرا میشه و هم پروپرتیِ Text ئه TextBlock ام همون مقداری میشه که وقتی اسلش نمیذاشتم بود . یعنی به درستی کار میکنه .
جالب تر اینکه وقتی بجای کاراکترِ اسلش "/" ، کاراکترِ بک اسلش "\" را میذارم ، همین ارور را هم نمیده و نتیجه اش هم مثل قبلی هاست .
جریان این چجوری هست و چرا این جوری هست؟
===================
پی نوشت :
- برای گرفتنِ شیِ پیش فرضِ CollectionView ، از متد CollectionViewSource.GetDefaultView باید استفاده کنیم .
- در این مقالات (که لینک داده شد) ، در جاهایی که درباره ی CollectionView صحبت میکنه ، در اغلبِ جاهایی که نامِ View را میبره ، منظورش شی های CollectionView هستند . منظورش از View ، کنترل ها و المنت ها و کلا لایه ی View ای که در MVVM میشناسیم ، نیست .
- با متدهای CollectionView.MoveCurrentToPrevious و CollectionView.MoveCurrentToNext ، میتونیم مقدار پروپرتیِ CollectionView.CurrentItem هر چی که باشه را یه دونه به جلو یا عقب در شیِ CollectionView مون انتخاب کنیم .
- عملیات sorting یا filtering روی مقدار CurrentItem از CollectionView مون میتونه تاثیر میذاره .
- مقدارِ مقدار CurrentItem ئه CollectionView ، بصورت پیش فرض ، مقدارِ صفر اُمین عضو از کالکشنِ Binding شده هست (بجز موقع sorting یا filtering یا اینکه کاربر نهایی ، در کنترلِ Binding شده ی مورد نظر ، آیتمی را انتخاب کنه یا برنامه نویس تغییری بده) .
درست گفتم؟
ببخشید خیلی زیاد شد .
خیلی ممنون استاد .