منظورم ساختن ControlTemplate برای TabItem ئه، اینکه کجا میسازیدش به استفاده خودتون بستگی داره.
خیلی ممنون استاد .
کدتون را از قسمت نقل قول حذف کردم چون خودم میخوام کد بدم ، محدودیت تعداد کاراکترهای پست ، اجازه بده .
اما منظورم این بود که در TabControl ، بخشِ زیرِ TabItem ها (در پست 116 که تصویرش هست) که Transparent هست را یه رنگی بشه داد تا خالی نباشه .
با این کد هم باز هم خالی هه .
حالا متوجه شدم باید چی کار کرد که در بخش آخر میگم .
برای شیء خاصی Style مقدار دهی نکنید، Style عمومی بسازید که برای هر TabItem ای قابل استفاده باشه.
بله .
اما اگه برای پروپرتی Template ئه مربوط به TabItem (نه اینکه پروپرتی Template ئه مربوط به TabControl) را بهش تمپلیت بدیم ، فقط همون یک دونه از TabItem ای را که مشخص کرده بودیم را مشخص میکنه و به بقیه ی TabItem ها کاری نداره .
چون ControlTemplate های TabControl و TabItem رو قاطی پاتی کردید. من در کد شما داخل ControlTemplate ئه TabItem یک توصیف TabPanel می بینم که IsItemsHost اش True ئه.
در کد مایکروسافت ببینید TabPanel کجا توصیف شده؟ در ControlTemplate ئه TabControl یا در ControlTemplate ئه TabItem؟
بله . خیلی ممنون
خیلی ساده. کد کلاسش، وقتی Panel ای مشخصه IsItemsHost رو True می کنه، IsItemsHostProperty به صاحبش که یک ItemsControl ئه سیگنال میده که این مقدار عوض شد.
اونم با یک متد OnIsItemsHostChanged ای که اجرا میشه ItemsHost اش رو تنظیم می کنه روی اون Panel و دیگه میدونه با کدوم Panel باید کار کنه و بهش دسترسی داره، هر وقت بخواد میتونه آیتم داخلش قرار بده.
یه چیزهایی متوجه شدم ولی نه دقیق
برای اضافه کردن آیتم ها کار خاصی نباید بکنید، کار کلاس همونه و اگه اختلالی در کارش ایجاد نکنید خودش انجامش میده.
صرفا اگه میخواهید برای TabControl ئه ControlTemplate بسازید باید طبق قالبی که در سایت مایکروسافت نمونه اش هست پیش برید.
کد های XAML رو اگه قاطی پاتی نکنید درست کار می کنند، فقط یک کمی دقت می خواد.
بله .
استاد ، این چیزهایی که میگم ، ببینین درسته؟ :
اول اینکه کنترل هایی که دارای آیتم هستند (مثل combobox و TabControl و ...) ، دارای بخشی بنام TabItem هستند . و پروپرتی ای بنام ItemContainerStyle دارند که میشه بهش استایل داد (و بنابراین Template هم میشه داد) که این استایل و تمپلیت ، استایل و شکل بخش آیتم ها را مشخص میکنه . در واقع ، وقتی به ItemContainerStyle ، استایل و تمپلیست میدیم ، اولا فقط در حیطه ی یک آیتم اِعمال میشه (یعنی این جور نیست که وقتی یه Grid ای در استایل و تمپلیتِ مربوط به ItemContainerStyle رسم میکنیم ، کلِ آیتم های موجود را شامل بشه و به اندازه ی کل آیتم های اون کنترل بشه . بلکه فقط به اندازه ی یک آیتم هست) و دوما ، استایل ای که دادیم ، استایلِ همه ی آیتم های موجود خواهد شد . یعنی همه ی آیتم ها ، اون استایل را برای خودشون رسم میکنن .
بنابراین چون در این پروپرتی ، فقط به اندازه ی هر آیتمِ اون کنترل میتونیم رسم انجام بدیم ، اگه بخوایم بیشتر از فضای اون آیتم ، رسم ای انجام بدیم ، توسط این پروپرتی ، نمیتونیم و باید برای کل اون کنترل (یعنی توسط پروپرتیِ Template یا پروپرتیِ Style اون کنترل) رسم انجام بدیم .
مثلا مثل همین کاری که میخواستم بدم و در بخشِ پایینِ آیتم های TabControl (پشت زمینه ی آیتم هاش) ، چیزی رسم کنم . چون در محدوده ی بیرونِ از آیتم هاست ، بنابراین توسط پروپرتیِ ItemContainerStyle نمیشه و باید توسط پروپرتیِ Template یا پروپرتیِ Style مربوط به TabControl ، این کار را انجام بدم .
یا اگه بخوایم دورِ کلِ آیتم های این کنترل ها (کنترل TabControl یا combobox) ، یه border رسم کنیم ، باز هم توسط پروپرتیِ ItemContainerStyle نمیشه و باید توسط پروپرتیِ Template یا پروپرتیِ Style مربوط به این کنترل ها ، این کار را انجام بدیم .
دوم اینکه پروپرتیِ Template ای که در کنترل ها هست ، باعث میشه کلِ اون کنترل را از نو رسم کنیم . اما همونطور که در نکته ی اول گفتم ، پروپرتیِ ItemContainerStyle ئه مربوط به اون کنترل ، باعث میشه استایل و تمپلیت هایی که فقط مربوط به بخش آیتم های اون کنترل هستند را رسم کنیم .
سوم اینکه در کنترل TabControl ، هر TabItem ، پروپرتی ای بنام Template و Style داره که بصورت اختصاصی میتونیم فقط استایل های مربوط به همون TabItem را تغییر بدیم (برخلاف پروپرتیِ ItemContainerStyle ئه TabControl که باهاش همه ی TabItem را میتونیم با هم به یک شکل ، استایل بدیم) .
بنابراین پروپرتی Template و Style ئه مربوط به TabItem ها ، زمانی به درد میخوره که بخوایم استایل یه آیتم خاص را تغییر بدیم . مثلا یه آیتم ، اندازه ی پیش فرض اش نسبت به بقیه ی آیتم ها بزرگ تر باشه یا هر تغییر دیگه ای .
چهارم اینکه در کنترل TabControl ها ، TabItem ، فقط بخشِ قسمتِ بالایی (سربرگ ها) را میگن (یعنی فقط بخشی که بصورت پیش فرض متن شون ، TabItem نوشته هست) . یعنی بخش محتوای TabControl (که داخل هر کدوم از صفحات شون ، کنترل های مختلف مون را قرار میدیم) ، جزء TabItem ها به حساب نمیان.
-----------------------------------
چیزی که میخواستم ، این بود استاد (حالا Background بوردر را ندادم) :
کد:
<!-- Simple TabControl
This template uses Simple TabItem for each Tab. The TabItems are placed in the TabPanel
Limitations : The Simple TabControl only allow the Tabs to be shown at the top of the Tab control. You can re-position the TabPanel to change this-->
<Style x:Key="SimpleTabControl" TargetType="{x:Type TabControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid KeyboardNavigation.TabNavigation="Local">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- TabPanel is a layout container which allows the TabItems to wrap and re-order when selected
The implementation knows to use this control because it is marked IsItemsHost = True -->
<Border Grid.Row="0" BorderBrush="Red" BorderThickness="1"/>
<TabPanel Grid.Row="0" Margin="0,0,4,-1" x:Name="HeaderPanel" Background="Transparent" IsItemsHost="True" Panel.ZIndex="1" KeyboardNavigation.TabIndex="1"/>
<Border Grid.Row="1" x:Name="Border" Background="{DynamicResource WindowBackgroundBrush}" BorderBrush="{DynamicResource SolidBorderBrush}" BorderThickness="1" CornerRadius="2" KeyboardNavigation.DirectionalNavigation="Contained" KeyboardNavigation.TabNavigation="Local" KeyboardNavigation.TabIndex="2">
<!-- The implementation switches the content. This control must be named PART_SelectedContentHost -->
<ContentPresenter Margin="4" x:Name="PART_SelectedContentHost" ContentSource="SelectedContent"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{DynamicResource DisabledForegroundBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource DisabledBorderBrush}" TargetName="Border"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
بعد استاد ، طبق کد زیر :
کد:
<Style x:Key="SimpleTabItem" TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border Margin="0,0,-4,0" x:Name="Border" Background="{DynamicResource LightBrush}" BorderBrush="{DynamicResource SolidBorderBrush}" BorderThickness="2,2,2,2" CornerRadius="2,12,0,0">
<ContentPresenter Margin="10,2" ContentSource="Header"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Panel.ZIndex" Value="100"/>
<Setter Property="Background" Value="{DynamicResource WindowBackgroundBrush}" TargetName="Border"/>
<Setter Property="BorderThickness" Value="1,1,1,0" TargetName="Border"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Border"/>
<Setter Property="BorderBrush" Value="{DynamicResource DisabledBorderBrush}" TargetName="Border"/>
<Setter Property="Foreground" Value="{DynamicResource DisabledForegroundBrush}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
اولا ContentPresenter ، لازم نیست که فقط برای کنترل هایی از نوع ContentControl بکار برده بشه . چون ContentPresenter که در کد بالا (برای Border) اومد ، اون Border که از نوع ContentControl نیست .
دوما ، پروپرتی ContentSource مربوط به ContentControl ، یعنی اینکه نام پروپرتی ای را بهش بدیم که محتوای اون را نشون بده؟ اینه قضیه اش؟
اگه اینه ، پس در کد اول که ContentSource="SelectedContent" هست ، اون SelectedContent چیه و از کجا آورد؟
اگه این نیست ، پس در کد دوم که ContentSource="Header" هست ، منظورش همون Header ئه مربوط به هر TabItem هه دیگه ؟ (چون نوع ControlTemplate مون ، TabItem هست دیگه) .
خیلی ممنون استاد .
ببخشید زیاد شد .