2013-05-07 136 views
6

我正在嘗試重新模板TextBox以使用兩個填充中間的邊框;但是,即使我明確將PART_ ContentHost上的填充設置爲零,控件的填充始終也應用於內部ScrollViewerTextBox模板填充問題

小例子:

<Style TargetType="{x:Type TextBox}"> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="{x:Type TextBox}"> 
       <Border Padding="{TemplateBinding Padding}" 
         BorderThickness="1" 
         BorderBrush="Black" 
         Background="LightBlue"> 
        <ScrollViewer Padding="0" Margin="0" Background="Turquoise" 
            x:Name="PART_ContentHost" /> 
       </Border> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

<TextBox Padding="15"/> 

結果是一個文本框,看起來像:[15 15 文本字段 15] 15]

,而我希望只是:15 文本字段] 15]

如何正確強制PART_ContentHost(scrollviewer/textfield)具有零填充?

回答

6

對我來說,這真的看起來像一個奇怪的錯誤,除非有人對此行爲有更好的解釋。

ScrollViewer(PART_ContentHost)內部使用Template像:

<ControlTemplate 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.Row="1" 
       Grid.Column="1" 
       Fill="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" /> 
    <ScrollContentPresenter x:Name="PART_ScrollContentPresenter" 
          Grid.Row="0" 
          Grid.Column="0" 
          Margin="{TemplateBinding Padding}" 
          CanContentScroll="{TemplateBinding CanContentScroll}" 
          CanHorizontallyScroll="False" 
          CanVerticallyScroll="False" 
          Content="{TemplateBinding Content}" 
          ContentTemplate="{TemplateBinding ContentTemplate}" /> 
    <ScrollBar x:Name="PART_VerticalScrollBar" 
       Grid.Row="0" 
       Grid.Column="1" 
       AutomationProperties.AutomationId="VerticalScrollBar" 
       Cursor="Arrow" 
       Maximum="{TemplateBinding ScrollableHeight}" 
       Minimum="0" 
       ViewportSize="{TemplateBinding ViewportHeight}" 
       Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" 
       Value="{Binding VerticalOffset, 
           Mode=OneWay, 
           RelativeSource={RelativeSource TemplatedParent}}" /> 
    <ScrollBar x:Name="PART_HorizontalScrollBar" 
       Grid.Row="1" 
       Grid.Column="0" 
       AutomationProperties.AutomationId="HorizontalScrollBar" 
       Cursor="Arrow" 
       Maximum="{TemplateBinding ScrollableWidth}" 
       Minimum="0" 
       Orientation="Horizontal" 
       ViewportSize="{TemplateBinding ViewportWidth}" 
       Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" 
       Value="{Binding HorizontalOffset, 
           Mode=OneWay, 
           RelativeSource={RelativeSource TemplatedParent}}" /> 
    </Grid> 
</ControlTemplate> 

感興趣的是:

<ScrollContentPresenter x:Name="PART_ScrollContentPresenter" 
         Grid.Row="0" 
         Grid.Column="0" 
         Margin="{TemplateBinding Padding}" 
         CanContentScroll="{TemplateBinding CanContentScroll}" 
         CanHorizontallyScroll="False" 
         CanVerticallyScroll="False" 
         Content="{TemplateBinding Content}" 
         ContentTemplate="{TemplateBinding ContentTemplate}" /> 

我們解決您的問題,您可以只設置有以0保證金,而不是{TemplateBinding Padding},你會得到你想要的輸出。

但是爲什麼我們需要這樣做呢?

TemplateBinding Padding似乎被忽略了上直接設置ScrollViewer這是在內部範圍,並挑選繼承自父填充值的值(Button),這是15

確定這很奇怪,但更糟糕的是它只適用於Padding。 Foreground,Background,Margin當直接設置在ScrollViewer上時,它們都會覆蓋TextBox的字段。我甚至可以確認將Padding直接使用TextBox中的使用情況轉移到了默認的樣式設置器,以查看是否有某個優先級案例是問題所在。

它似乎不是。得到相同的輸出。

填充在System.Windows.Controls.Control中定義,其中前景和背景都是從ScrollViewer繼承而來的。不知道爲什麼填充本身的行爲有所不同。

我也試圖改變演示者像

<ScrollContentPresenter x:Name="PART_ScrollContentPresenter" 
         Grid.Row="0" 
         Grid.Column="0" 
         Margin="{TemplateBinding Margin}" 
         CanContentScroll="{TemplateBinding CanContentScroll}" 
         CanHorizontallyScroll="False" 
         CanVerticallyScroll="False" 
         Content="{TemplateBinding Padding}" 
         ContentTemplate="{TemplateBinding ContentTemplate}" /> 

它打印的15,15,15,15。不要爲Margin這樣做。

{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ScrollViewer}}, Path=Padding}綁定的效果相同。

我看到一個帖子說ScrollViewer沒有傳遞給它的孩子設置的屬性。真的不知道,因爲如果是這樣的話,BackgroundMargin和排序怎麼樣都可以超越? Padding有什麼特別之處?如果它是有效的行爲,我真的不知道如何擺脫這種行爲沒有模板ScrollViewer以及它是一個令人困惑的實現。

+0

非常感謝您的詳細和經過充分測試的答案!我非常感謝關於scrollviewer模板的輸入和信息。這當然是一個奇怪的例子,這對我來說沒有多大意義。 – 2013-05-07 19:51:16

3

這種奇怪的行爲來自TextBoxBase。 它覆蓋的元數據爲它的一些依賴屬性,爲Padding財產,它看起來像:

Control.PaddingProperty.OverrideMetadata(
    typeof (TextBoxBase), 
    new FrameworkPropertyMetadata(
     new PropertyChangedCallback(TextBoxBase.OnScrollViewerPropertyChanged))); 

如果採取OnScrollViewerPropertyChanged處理程序一看,你會發現,它通過改變屬性的值,它是ScrollViewer中:

if (newValue == DependencyProperty.UnsetValue) 
    textBoxBase.ScrollViewer.ClearValue(e.Property); 
    else 
    textBoxBase.ScrollViewer.SetValue(e.Property, newValue); 

因此,無論您在Control Template中設置了什麼Padding值,它在運行時都會被TextBox的本地值覆蓋。

爲了彌補這種填充你可以在模板負邊距設置爲ScrollViewer中:

<ScrollViewer 
    x:Name="PART_ContentHost" 
    Margin="{TemplateBinding Padding, Converter={StaticResource InvertThicknessConverter}}" 
/> 

其中InvertThicknessConverter是值轉換器,它否定了通過厚度值的每個組件:

public class InvertThicknessConverter: IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     if (value is Thickness) return InvertThickness((Thickness)value); 
     return value; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     if (value is Thickness) return InvertThickness((Thickness)value); 
     return value; 
    } 

    private static Thickness InvertThickness(Thickness value) 
    { 
     return new Thickness(-value.Left, -value.Top, -value.Right, -value.Bottom); 
    } 
} 
+0

有趣的發現!感謝您的進一步細節。雖然我可能會繼續使用自定義滾動查看器樣式來解決該問題,但擁有選項並瞭解問題來自哪裏是非常好的。 – 2014-10-10 13:37:07

+0

這實際上比接受的答案更好,因爲您只是使用轉換器而不是覆蓋ControlTemplate;然而,它只適用於綁定到ScrollViewer的'Padding',_not_'Margin',在我的情況下。 – 2017-04-30 19:10:44

0

我跑進在DataGridColumnHeader上設置Padding屬性時出現此問題,並通過指定一個填充屬性關閉但不等於零來解決該問題:

<Style x:Key="CustomHeader" TargetType="DataGridColumnHeader" BasedOn="{StaticResource {x:Type DataGridColumnHeader}}"> 
    <!-- Why you might ask do we need a value that is near but not actually 0? No idea, but if it is not there, "4" is used. --> 
    <!-- See http://stackoverflow.com/questions/16424739/textbox-template-padding-issue --> 
    <Setter Property="Padding" Value="0,0,0.000000000001,0" /> 
</Style>