2013-05-07 7 views
6

Ich versuche, eine TextBox Vorlage neu zu erstellen, zwei Grenzen mit Padding dazwischen zu haben; Aber selbst wenn ich die Auffüllung von PART_ ContentHost explizit auf Null setze, wird das Padding für das Steuerelement immer auch auf das innere ScrollViewer angewendet.TextBox Vorlage Polsterung Problem

Kleines Beispiel:

<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"/> 

Das Ergebnis ist eine Textbox, die wie folgt aussieht:

während ich erwartet hatte nur [15 [15 Textfeld 15] 15] [15 [Textfeld] 15]

Wie erzwinge ich richtig den PART_ContentHost (scrollviewer/Textfeld), um eine Nullauffüllung zu haben?

Antwort

6

Das sieht wirklich wie ein seltsamer Fehler für mich aus, es sei denn jemand hat eine bessere Erklärung für dieses Verhalten.

ScrollViewer (PART_ContentHost) verwendet intern ein Template wie:

<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> 

Das interessante Bit ist:

<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}" /> 

Jetzt ist Ihr Problem zu beheben Sie nur die Margin 0 bis dort einstellen können statt {TemplateBinding Padding} und Sie erhalten Ihre gewünschte Ausgabe.

Aber warum mussten wir das tun?

TemplateBinding Padding scheint den Wert auf den ScrollViewer direkt eingestellt ignoriert werden, die in dem inneren Umfang und nehmen den Padding-Wert aus dem Elternteil vererbt (Button), die 15. ist

Ok, das ist seltsam, aber was noch schlimmer ist, Es ist nur für Padding. Foreground, Background, Margin sind alle in Ordnung, wenn sie direkt auf ScrollViewer setzen, überschreiben sie die TextBox Felder. Ich selbst zu bestätigen, bewegte das Padding Set direkt auf die TextBox im Einsatz zu einem Standard-Style-Setter, um zu sehen, ob einige Präzedenzfall das Problem war.

Es schien nicht zu sein. Habe den gleichen Ausgang.

Padding ist in definiert, die die gleiche Klasse ist Vordergrund und Hintergrund sind davon ScrollViewer erbt. Nicht sicher, warum Padding sich anders verhält.

ich auch versucht, den Vortragenden zu so etwas wie

Wechsel
<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}" /> 

Es Druck ist 15,15,15,15. Tut das nicht für die Margin.

Gleicher Effekt mit einer {Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ScrollViewer}}, Path=Padding} Bindung.

Ich sah einen Beitrag sagen, dass ScrollViewer Eigenschaften auf es nicht zu seinen Kindern übergeben wird.Nicht wirklich, dass, wenn das der Fall war, wie Background, Margin und Arten in Ordnung sein könnten, um zu überfahren? Was ist so besonders an Padding? Wenn es gültiges Verhalten ist, sehe ich nicht wirklich, wie man dieses Verhalten loswerden kann, ohne die ScrollViewer Templating auch, und es ist eine verwirrende Implementierung.

+0

Vielen Dank für die detaillierte und gut getestete Antwort! Ich schätze die Eingaben und Informationen zur Scrollviewer-Vorlage. Das ist sicher ein seltsamer Fall, der mir wenig Sinn macht. –

3

Dieses seltsame Verhalten kommt von TextBoxBase. Sie überschreibt Metadaten für einige seiner Eigenschaften Abhängigkeit und für die Padding Eigenschaft sieht es so aus:

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

Wenn Sie einen Blick auf OnScrollViewerPropertyChanged Handler nehmen werden Sie feststellen, dass sie den Wert der geänderten Eigenschaft geht es Scroll ist:

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

Also, egal was Padding Wert richte Sie in Control Template, wird es mit den lokalen Wert von TextBox in Laufzeit überschrieben.

diese Polsterung Um dies zu kompensieren Sie negative Marge auf Scroll in Vorlage festlegen:

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

wo InvertThicknessConverter Werteumwandler ist, die jede Komponente übergeben Dickenwert negiert:

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

Interessanter Fund! Danke für weitere Details. Während ich wahrscheinlich weiterhin einen benutzerdefinierten Scrollviewer-Stil verwende, um das Problem zu umgehen, ist es großartig, Optionen zu haben und zu verstehen, wo das Problem herkommt. –

+0

Das ist eigentlich besser als die angenommene Antwort, weil Sie nur einen Konverter verwenden, anstatt ein 'ControlTemplate' zu ​​überschreiben; Es funktioniert jedoch nur, wenn Sie in meinem Fall an 'ScrollViewer' 'Padding', _not_' Margin' binden. –

0

Ich lief in Dieses Problem beim Festlegen der Padding -Eigenschaft auf DataGridColumnHeader, und habe es durch Festlegen einer Polsterungseigenschaft schließen, aber nicht gleich Null:

<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>