CustomControl verschwindet bei globalem style

  • WPF
  • .NET (FX) 4.5–4.8

Es gibt 4 Antworten in diesem Thema. Der letzte Beitrag () ist von Fakiz.

    CustomControl verschwindet bei globalem style

    Guten Abend,
    Ich hab ein CustomControl (TextBox mit Placeholder) welches in einem Grid angezeigt werden soll.
    Da ich mehere dieser Textboxen brauche und alle in Spalte 2 angezeigt werden sollen wollte ich einen globalen style dafür definieren.

    XML-Quellcode

    1. <Style TargetType="{x:Type controls:TextBoxEx}">
    2. <Setter Property="Grid.Column" Value="1"/>
    3. <Setter Property="Grid.ColumnSpan" Value="2"/>
    4. </Style>


    Wenn ich das tue verschwindet die TextBox aber. Dabei ist es egal ob ich Setter im Style habe oder nicht. Setze ich die Spalte inline direkt an der TextBox wird sie angezeigt.
    Das funktioniert:

    XML-Quellcode

    1. <controls:TextBoxEx Grid.Row="3" Grid.Column="1"
    2. Text="Hallo" Placeholder="..."/>


    Hat jemand eine Ahnung woran das liegen könnte.
    Wie sieht die TextBoxEx aus?
    Ist es ein UserControl oder ein CustomControl?

    Probier mal sowas:

    XML-Quellcode

    1. <controls:TextBoxEx Content="Hallo1" Margin="0,0"/>
    2. <controls:TextBoxEx Content="Hallo2" Margin="0,20"/>
    3. <controls:TextBoxEx Content="Hallo3" Margin="0,40"/>

    Achte darauf das die Grid.Row hoch genug ist um die Controls anzuzeigen.

    Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von „Amro“ ()

    TextBoxEx ist ein CustomControl (Sieht ungefähr so aus. Original Projekt liegt zuhause, Padding könnte vom Original abweichen):
    CSharp

    C#-Quellcode

    1. public class TextBoxEx : Control
    2. {
    3. public Brush PlaceholderForeground
    4. {
    5. get => (Brush)GetValue(PlaceholderForegroundProperty);
    6. set => SetValue(PlaceholderForegroundProperty, value);
    7. }
    8. public static readonly DependencyProperty PlaceholderForegroundProperty;
    9. public Brush PlaceholderBackground
    10. {
    11. get => (Brush)GetValue(PlaceholderBackgroundProperty);
    12. set => SetValue(PlaceholderBackgroundProperty, value);
    13. }
    14. public static readonly DependencyProperty PlaceholderBackgroundProperty;
    15. public string Placeholder
    16. {
    17. get => (string)GetValue(PlaceholderProperty);
    18. set => SetValue(PlaceholderProperty, value);
    19. }
    20. public static readonly DependencyProperty PlaceholderProperty;
    21. public new string Text
    22. {
    23. get => (string)GetValue(TextProperty);
    24. set => SetValue(TextProperty, value);
    25. }
    26. public new static readonly DependencyProperty TextProperty;
    27. static TextBoxEx()
    28. {
    29. PlaceholderForegroundProperty = DependencyProperty.Register(nameof(PlaceholderForeground), typeof(Brush), typeof(TextBoxEx), new PropertyMetadata(Brushes.Gray));
    30. PlaceholderBackgroundProperty = DependencyProperty.Register(nameof(PlaceholderBackground), typeof(Brush), typeof(TextBoxEx), new PropertyMetadata(Brushes.Transparent));
    31. PlaceholderBackgroundProperty = DependencyProperty.Register(nameof(Placeholder), typeof(string), typeof(TextBoxEx), new PropertyMetadata(default(string)));
    32. TextProperty = DependencyProperty.Register(nameof(Text), typeof(string), typeof(TextBoxEx), new PropertyMetadata(default(string)));
    33. DefaultStyleKeyProperty.OverrideMetadata(typeof(TextBoxEx), new FrameworkPropertyMetadata(typeof(TextBoxEx)));
    34. }
    35. }



    XAML

    XML-Quellcode

    1. <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    2. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    3. xmlns:local="clr-namespace:CustomControls">
    4. <Style TargetType="{x:Type local:TextBoxEx}">
    5. <Setter Property="Template">
    6. <Setter.Value>
    7. <ControlTemplate TargetType="{x:Type local:TextBoxEx}">
    8. <Border Background="{TemplateBinding Background}">
    9. <Grid>
    10. <Grid.Resources>
    11. <Style TargetType="{x:Type Label}">
    12. <Setter Property="Visibility" Value="Collapsed"/>
    13. <Setter Property="VerticalContentAlignment" Value="Center"/>
    14. <Setter Property="VerticalAlignment" Value="Stretch"/>
    15. <Style.Triggers>
    16. <DataTrigger Binding="{Binding ElementName=TextBox, Path=Text.Length}" Value="0">
    17. <Setter Property="Visibility" Value="Visible" />
    18. </DataTrigger>
    19. </Style.Triggers>
    20. </Style>
    21. </Grid.Resources>
    22. <Label FontSize="{Binding ElementName=TextBox, Path=FontSize}"
    23. Foreground="{TemplateBinding PlaceholderForeground}"
    24. Background="{TemplateBinding PlaceholderBackground}"
    25. Content="{TemplateBinding Placeholder}"
    26. Padding="2 1"/>
    27. <TextBox x:Name="TextBox"
    28. Text="{TemplateBinding Text}"
    29. Foreground="{TemplateBinding Foreground}"
    30. Height="{TemplateBinding Height}"
    31. VerticalAlignment="Stretch"
    32. VerticalContentAlignment="Center"
    33. Background="Transparent"/>
    34. </Grid>
    35. </Border>
    36. </ControlTemplate>
    37. </Setter.Value>
    38. </Setter>
    39. </Style>
    40. </ResourceDictionary>



    Wie gesagt die TextBox wird angezeigt wenn ich Grid.Column inline zuweise. Für mich als WPF-Leihe sieht das eher so aus als würde ich den Style und somit das Template der TextBoxEx überschreiben.
    Ohne Template und vernünfite Basisklasse dürfte es dann ja nichts zu Rendern geben.

    Ich hab jetzt noch nicht auspropiert was passiert wenn ich den Style, in dem ich die Grid.Column setze, vom TextBoxEx Style ableite (BasedOn). Das wäre im Moment das einzige was mir einfallen würde.
    Jetzt auf den ersten Blick finde ich das etwas komisch.
    PlaceholderBackground wird zweimal und Placeholder gar nicht.
    Und es wird einmal als Placeholder registriert. Siehe Bild.

    Das Beispiel ist nur etwas korregiert, du müsstes es noch für dich anpassen.
    In dein MainWindow nimmst du einfach ein StackPanel und setzt es auf Grid.Column=1.

    TextBoxEx - Control
    Spoiler anzeigen

    C#-Quellcode

    1. public class TextBoxEx : Control
    2. {
    3. public Brush PlaceholderForeground
    4. {
    5. get => (Brush)GetValue(PlaceholderForegroundProperty);
    6. set => SetValue(PlaceholderForegroundProperty, value);
    7. }
    8. public static readonly DependencyProperty PlaceholderForegroundProperty;
    9. public Brush PlaceholderBackground
    10. {
    11. get => (Brush)GetValue(PlaceholderBackgroundProperty);
    12. set => SetValue(PlaceholderBackgroundProperty, value);
    13. }
    14. public static readonly DependencyProperty PlaceholderBackgroundProperty;
    15. public string Placeholder
    16. {
    17. get => (string)GetValue(PlaceholderProperty);
    18. set => SetValue(PlaceholderProperty, value);
    19. }
    20. public static readonly DependencyProperty PlaceholderProperty;
    21. public string Text
    22. {
    23. get => (string)GetValue(TextProperty);
    24. set => SetValue(TextProperty, value);
    25. }
    26. public static readonly DependencyProperty TextProperty;
    27. static TextBoxEx()
    28. {
    29. PlaceholderForegroundProperty = DependencyProperty.Register(nameof(PlaceholderForeground), typeof(Brush), typeof(TextBoxEx), new PropertyMetadata(Brushes.Gray));
    30. PlaceholderBackgroundProperty = DependencyProperty.Register(nameof(PlaceholderBackground), typeof(Brush), typeof(TextBoxEx), new PropertyMetadata(Brushes.Transparent));
    31. PlaceholderProperty = DependencyProperty.Register(nameof(Placeholder), typeof(string), typeof(TextBoxEx), new PropertyMetadata(default(string)));
    32. TextProperty = DependencyProperty.Register(nameof(Text), typeof(string), typeof(TextBoxEx), new PropertyMetadata(default(string)));
    33. DefaultStyleKeyProperty.OverrideMetadata(typeof(TextBoxEx), new FrameworkPropertyMetadata(typeof(TextBoxEx)));
    34. }
    35. }


    Style
    Spoiler anzeigen

    XML-Quellcode

    1. <Style TargetType="{x:Type local:TextBoxEx}">
    2. <Setter Property="Template">
    3. <Setter.Value>
    4. <ControlTemplate TargetType="{x:Type local:TextBoxEx}">
    5. <Border Background="{TemplateBinding Background}">
    6. <Grid>
    7. <Label x:Name="labelEx"
    8. Foreground="{TemplateBinding PlaceholderForeground}"
    9. Background="{TemplateBinding PlaceholderBackground}"
    10. Content="{TemplateBinding Placeholder}"
    11. Padding="2 1" Visibility="Hidden"/>
    12. <TextBox x:Name="textBoxEx"
    13. Text="{TemplateBinding Text}"
    14. Foreground="{TemplateBinding Foreground}"
    15. Height="{TemplateBinding Height}"
    16. VerticalAlignment="Stretch"
    17. VerticalContentAlignment="Center"
    18. Background="Transparent"
    19. />
    20. </Grid>
    21. </Border>
    22. <ControlTemplate.Triggers>
    23. <DataTrigger Binding="{Binding ElementName=textBoxEx, Path=Text.Length}" Value="0">
    24. <Setter Property="Visibility" Value="Visible" TargetName="labelEx"/>
    25. </DataTrigger>
    26. </ControlTemplate.Triggers>
    27. </ControlTemplate>
    28. </Setter.Value>
    29. </Setter>
    30. </Style>



    MainWindow
    Spoiler anzeigen

    XML-Quellcode

    1. <StackPanel Grid.Column="1">
    2. <local:TextBoxEx Placeholder="***" Width="150" Margin="10" PlaceholderBackground="Red" PlaceholderForeground="Yellow" />
    3. <local:TextBoxEx Placeholder="xxx" Width="150" Margin="10" PlaceholderBackground="Red" PlaceholderForeground="Yellow" />
    4. <local:TextBoxEx Placeholder="###" Width="150" Margin="10" PlaceholderBackground="Red" PlaceholderForeground="Yellow" />
    5. <local:TextBoxEx Placeholder="---" Width="150" Margin="10" PlaceholderBackground="Red" PlaceholderForeground="Yellow" />
    6. </StackPanel>



    Bilder
    • placeh.png

      27,91 kB, 1.360×291, 72 mal angesehen

    Dieser Beitrag wurde bereits 7 mal editiert, zuletzt von „Amro“ ()

    Erstmal danke für deine Mühe. Mit dem PlaceholderBackground hast du recht allerdings ist der gezeigte Code nicht 1:1 der origianle.
    Das mit dem Stackpanel löst leider das Problem nicht wirklich.

    Aber wie bereits vermutet wird der Style des CustomControl überschrieben, durch das Vererben des Basisstyles funktioniert es.
    Lösung

    XML-Quellcode

    1. <Style TargetType="{x:Type controls:TextBoxEx}" BasedOn="{StaticResource {x:Type controls:TextBoxEx}}">
    2. <Setter Property="Grid.Column" Value="1"/>
    3. <Setter Property="Grid.ColumnSpan" Value="2"/>
    4. </Style>