custom template for a textBox that does not behave as I want on IsEnabled = false
my issue is a bit similar to this one: Having an issue with my TextBox control template
but I'd like to go a little further:
my issue is simple: I have templated controls (labels, textboxes, checkboxes and so on...). Each control has default value that can all be overriden at runtime by setting the control instance's property value. And no matter what value was set to a property, the values that I decided to use when IsEnabled = false should prevail.
now, I know that Value precedence in WPF prevents an easy implementation for this behaviour (as I learned in an other question: http://msdn.microsoft.com/en-us/library/ms743230.aspx)
but I managed to find a workaround that does the job pretty well, except for the Foreground property in a TextBox. (and only this specific case)
so, just taking care of the foreground value, here is what I do on a Label: (I got rid of all the other properties for more clarity)
<Style TargetType="Label">
<Setter Property="Foreground" Value="Blue"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Label">
<Border>
<ContentPresenter Name="ContentSite"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter TargetName="ContentSite" Property="TextBlock.Foreground" Value="Red"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
So basically, by default, a Label will have a Blue text, that I can override with, say, green by doing: myLabel.Foreground = Brushes.Green
in code开发者_C百科 behind, and then, no matter what I set, If I write: MyLabel.IsEnabled = False
, the text will become Red.
and this technique works great. (i.e.: this line in xaml will output a red text: <Label Foreground="Green" IsEnabled="False" />
). It works the same way with all other controls.
but when trying to reproduce this with a textBox, it does not work at all.
here's my code:
<Style TargetType="TextBox">
<Setter Property="Foreground" Value="Blue"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Grid>
<Border Name="Border">
<ScrollViewer x:Name="PART_ContentHost" />
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="PART_ContentHost" Property="Foreground" Value="Red"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I tried to add Foreground="{TemplateBinding Foreground}"
on the PART_ContentHost with no success.
I suspect this has something to do with the fact that PART_ContentHost is a scrollviewer and there is some kind of hidden (at least from me) inheritance going on.
the only other explanation I can find is that the TextBox class has some kind of special treatment that hardcodes a link between the control itself and its PART_ContentHost part (binding or propertychanged event or something else?)
if somebody could explain this to me, this would be great! if somebody could even provide a nice solution (one that does not involve a nasty hack like the one I'm using at the moment but will not show here so as not to cause major eye injury to the reader), this would be even greater!
By default, that ScrollViewer is itself templated to look like this:
<ControlTemplate x:Key="ScrollViewerControlTemplate1" TargetType="{x:Type ScrollViewer}">
<Grid x:Name="Grid" Background="{TemplateBinding Background}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Rectangle x:Name="Corner" Grid.Column="1" Fill="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" Grid.Row="1"/>
<ScrollContentPresenter x:Name="PART_ScrollContentPresenter" CanContentScroll="{TemplateBinding CanContentScroll}" CanHorizontallyScroll="False" CanVerticallyScroll="False" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Grid.Column="0" Margin="{TemplateBinding Padding}" Grid.Row="0"/>
<ScrollBar x:Name="PART_VerticalScrollBar" AutomationProperties.AutomationId="VerticalScrollBar" Cursor="Arrow" Grid.Column="1" Maximum="{TemplateBinding ScrollableHeight}" Minimum="0" Grid.Row="0" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportHeight}"/>
<ScrollBar x:Name="PART_HorizontalScrollBar" AutomationProperties.AutomationId="HorizontalScrollBar" Cursor="Arrow" Grid.Column="0" Maximum="{TemplateBinding ScrollableWidth}" Minimum="0" Orientation="Horizontal" Grid.Row="1" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportWidth}"/>
</Grid>
</ControlTemplate>
I got that out of the TextBox by using Blend, by the way.
I'm betting that if you add your triggers to that ScrollContentPresenter
in that template the way you did it to the ContentPresenter
in the Label that it'll work for you.
精彩评论