Charles Clayton
Charles Clayton

Reputation: 17956

How to style auto-generated elements in xaml

I'm using this extension this toolkit, it automatically adds a TextBox to the top of each DataGrid column for filtering from the following code.

<DataGrid ColumnHeaderStyle="{StaticResource {ComponentResourceKey 
       TypeInTargetAssembly={x:Type filter:DataGridHeaderFilterControl}, 
       ResourceId=DataGridHeaderFilterControlStyle}}" >

However, the added column header and the textboxes have a different style from what I want.

So I can do this to style the column header, but it won't change the textboxes.

<Style x:Key="FilterHeader"
        BasedOn="{StaticResource {ComponentResourceKey TypeInTargetAssembly={x:Type filter:DataGridHeaderFilterControl},
                                                        ResourceId=DataGridHeaderFilterControlStyle}}"
        TargetType="{x:Type DataGridColumnHeader}">

    <Setter Property="Foreground" Value="Blue" />

</Style>

...

<DataGrid ColumnHeaderStyle="{DynamicResource FilterHeader}">

I tried putting this inWindow.Resources to see if it had an effect on the textboxes. It changed my other textboxes it doesn't have any effect on the textboxes created by the extension.

<Style TargetType="TextBox">
    <Setter Property="Foreground" Value="Blue" />
</Style>

But no dice. The only thing I've found that works is this:

    public void DataGrid_OnLoad(object sender, RoutedEventArgs e)
    {
        IEnumerable<System.Windows.Controls.TextBox> collection =
            FindVisualChildren<System.Windows.Controls.TextBox>(TitleBar);

        foreach (System.Windows.Controls.TextBox tb in collection)
        {
            tb.Foreground = Brushes.Blue;
        }
    }

    public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
    {
        if (depObj != null)
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
                if (child != null && child is T)
                {
                    yield return (T)child;
                }

                foreach (T childOfChild in FindVisualChildren<T>(child))
                {
                    yield return childOfChild;
                }
            }
        }
    }

But that seems like a garbage way of doing it. How can I do this purely in xaml or at least more cleanly in C#?

Upvotes: 0

Views: 359

Answers (1)

scartag
scartag

Reputation: 17680

From looking through the source code, i noticed that the TextBox isn't really a textbox but a subclass of Textbox. DelayTextBox

So you could just modify your style to target that instead.

<Style TargetType="DelayTextBox">
    <Setter Property="Foreground" Value="Blue" />
</Style>

I haven't tried it but it should work.

Update

Finally found the issue. The styles should be defined within a style of their parent.

<Style TargetType="{x:Type filter:DataGridColumnFilter}">
    <Style.Resources>

        <Style TargetType="{x:Type support:DelayTextBox}">
            <Setter Property="Foreground" Value="Blue" />
            <Setter Property="FontWeight" Value="Bold"/>
        </Style>

        <Style TargetType="{x:Type ComboBox}">
            <Setter Property="Foreground" Value="Blue" />
            <Setter Property="FontWeight" Value="Bold"/>
        </Style>
    </Style.Resources>
</Style>

I've added the comboxbox since i assume you'd want that too. you can take out the setter for bold as needed .. was using it to test.

Upvotes: 1

Related Questions