pastillman
pastillman

Reputation: 1134

How do you change the style of the ListView column reorder separator indicator?

How do you change the style of the ListView column reorder separator indicator? (The blue line that appears when you try to reorder a column, pictured below)

enter image description here

The following oddly only changes the height :

<ListView>
    <ListView.Resources>
        <Style TargetType="{x:Type Separator}">
            <Setter Property="Height"
                    Value="5" />
            <Setter Property="Foreground"
                    Value="Red" />
            <Setter Property="Background"
                    Value="Red" />
        </Style>
    </ListView.Resources>
    <ListView.View>
        <GridView >
            <GridViewColumn Header="First Name"
                            Width="100" />
            <GridViewColumn Header="Last Name"
                            Width="100" />
        </GridView>
    </ListView.View>
</ListView>

I've tried a bunch of things, including

but no luck.

Upvotes: 2

Views: 801

Answers (2)

pastillman
pastillman

Reputation: 1134

So it turns out the template is actually hard coded. See the source code for GridViewHeaderRowPresenter. AddIndicator() presented below

// Create the indicator for column re-ordering
    private void AddIndicator()
    {
        Separator indicator = new Separator();
        indicator.Visibility = Visibility.Hidden;

        // Indicator style:
        //
        // <Setter Property="Margin" Value="0" />
        // <Setter Property="Width" Value="2" />
        // <Setter Property="Template">
        //   <Setter.Value>
        //     <ControlTemplate TargetType="{x:Type Separator}">
        //        <Border Background="#FF000080"/>
        //     </ControlTemplate>
        //   </Setter.Value>
        // </Setter>

        indicator.Margin = new Thickness(0);
        indicator.Width = 2.0;

        FrameworkElementFactory border = new FrameworkElementFactory(typeof(Border));
        border.SetValue(Border.BackgroundProperty, new SolidColorBrush(Color.FromUInt32(0xFF000080)));

        ControlTemplate template = new ControlTemplate(typeof(Separator));
        template.VisualTree = border;
        template.Seal();

        indicator.Template = template;

        InternalChildren.AddInternal(indicator);
        _indicator = indicator;
    }

here is the workaround I used (which can easily be turned into an attached property)

void ListView_Loaded(object sender, RoutedEventArgs e)
    {
        var listView = sender as ListView;
        if (listView != null)
        {
            var gvhrp = FindFirstVisual<GridViewHeaderRowPresenter>(listView);
            if (gvhrp != null)
            {
                var separator = FindFirstVisual<Separator>(gvhrp);
                if (separator != null)
                {
                    separator.IsVisibleChanged += delegate
                    {
                        var border = FindFirstVisual<Border>(separator);
                        if (border != null)
                        {
                            border.Background = Brushes.Red;
                        }
                    };
                }
            }
        }
    }

    T FindFirstVisual<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)
                {
                    return (T)child;
                }

                var result = FindFirstVisual<T>(child);
                if (result != null)
                {
                    return result;
                }
            }
        }

        return null;
    }

Upvotes: 1

MDoobie
MDoobie

Reputation: 282

Well, It is a little bit complicated... In order to that you have to create a style for the Thumb.

For example (the extracted default style using Blend):

<Style x:Key="GridViewColumnHeaderGripper" TargetType="{x:Type Thumb}">
        <Setter Property="Canvas.Right" Value="-9"/>
        <Setter Property="Width" Value="18"/>
        <Setter Property="Height" Value="{Binding ActualHeight, RelativeSource={RelativeSource TemplatedParent}}"/>
        <Setter Property="Padding" Value="0"/>
        <Setter Property="Background" Value="{StaticResource GridViewColumnHeaderBorderBackground}"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Thumb}">
                    <Border Background="Transparent" Padding="{TemplateBinding Padding}">
                        <Rectangle Fill="{TemplateBinding Background}" HorizontalAlignment="Center" Width="1"/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Then you have to create a GridViewColumnHeaderStyle. For example (the extracted default style using Blend. I've deleted some triggers for the sake of simplicity):

        <Style x:Key="GridViewColumnHeaderStyle1" TargetType="{x:Type GridViewColumnHeader}">
        <Setter Property="HorizontalContentAlignment" Value="Center"/>
        <Setter Property="VerticalContentAlignment" Value="Center"/>
        <Setter Property="Background" Value="{StaticResource GridViewColumnHeaderBackground}"/>
        <Setter Property="BorderBrush" Value="{StaticResource GridViewColumnHeaderBorderBackground}"/>
        <Setter Property="BorderThickness" Value="0"/>
        <Setter Property="Padding" Value="2,0,2,0"/>
        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type GridViewColumnHeader}">
                    <Grid SnapsToDevicePixels="true">
                        <Border x:Name="HeaderBorder" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="0,1,0,1" Background="{TemplateBinding Background}">
                            <Grid>
                                <Grid.RowDefinitions>
                                    <RowDefinition MaxHeight="7"/>
                                    <RowDefinition/>
                                </Grid.RowDefinitions>
                                <Rectangle x:Name="UpperHighlight" Fill="#FFE3F7FF" Visibility="Collapsed"/>
                                <Border Padding="{TemplateBinding Padding}" Grid.RowSpan="2">
                                    <ContentPresenter x:Name="HeaderContent" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="0,0,0,1" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                                </Border>
                            </Grid>
                        </Border>
                        <Border x:Name="HeaderHoverBorder" BorderThickness="1,0,1,1" Margin="1,1,0,0"/>
                        <Border x:Name="HeaderPressBorder" BorderThickness="1,1,1,0" Margin="1,0,0,1"/>
                        <Canvas>
                            <Thumb x:Name="PART_HeaderGripper" Style="{StaticResource GridViewColumnHeaderGripper}"/>
                        </Canvas>
                    </Grid>
            </ControlTemplate>
            </Setter.Value>
        </Setter>

Of course, in these styles, you can change anything you want. Probably you have to because these are just the default styles as I mentined before.

Upvotes: 0

Related Questions