简体   繁体   中英

How do I find the image in a WPF Datagrid ColumnHeader so I can change the image?

I'm attempting to implement Excel-like column filtering and sorting. To do this, I used a DataTemplate to define the Column Header.

    <DataGrid x:Name="dataGrid" HorizontalAlignment="Stretch"  VerticalAlignment="Stretch" CanUserSortColumns="False">
        <DataGrid.Resources>
            <Style TargetType="{x:Type DataGridColumnHeader}">
                <Setter Property="ContentTemplate">
                    <Setter.Value>
                        <DataTemplate>
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="23"/>
                                    <ColumnDefinition Width="*"/>
                                </Grid.ColumnDefinitions>
                                <Button x:Name="ExcelFilterButton" Tag="{Binding}" Click="ExcelFilterButton_Click" Margin="0,0,0,0" BorderThickness="0" Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}" Focusable="False" Grid.Column="0">
                                    <Image Source="Resources\NoSortNoFilter.png" Width="19" Height="19" />
                                </Button>
                                <TextBlock Text="{Binding}" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="1" />
                            </Grid>
                        </DataTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </DataGrid.Resources>
    </DataGrid>

And it comes out nicely .

I tried using VisualTreeHelper to find the image from the Column Header, but the Header property is a string. I've tried using the HeaderStyle and HeaderTemplate properties also but to no avail.

Using a WPF Spy program called Snoop, I can see the image in there, but still can't figure out how to access it in code. The reason I need to access it in code is to change the image based on whether that column is sorted and/or filtered. (Could this be done in XAML?)

Ok, I figured out how to do it. This most likely not the right way to do it, but I found a way that works.

To give you a little about the process.

  1. The user clicks a header button. The buttons Tag property is bound to the column header.
  2. The click event handler instantiates the context menu and sets its Tag to equal the button Tag.
  3. The user clicks on a menu item.
  4. The event handler sends the Context Menu Tag property and image name to the routine that finds the button, and then the image in the button, and changes the image.

now for the code.

The button click event handler:

    Private Sub ExcelFilterButton_Click(sender As Object, e As RoutedEventArgs)
        With DirectCast(Resources("sortContextMenu"), ContextMenu)
            .Tag = DirectCast(sender, Button).Tag
            .IsOpen = True
        End With
    End Sub

The menu item click event handler

Private Sub ContextMenuItem_Click(Sender As Object, e As RoutedEventArgs)
    If TypeOf Sender Is MenuItem Then
        'just testing, of course this isn't all this handler does.
        SetColumnSortImage(Sender.Tag, "Filtered")
    End If
End Sub

The SetColumnSortImage routine, which calls the two following routines.

Private Sub SetColumnSortImage(Tag As String, ImageName As String)
    Dim btn As Button = Nothing
    GetSortButton(Of Button)(dataGrid, Tag, btn)
    If btn IsNot Nothing Then
        Dim img As Image = GetChildOfType(Of Image)(btn)
        img.Source = New BitmapImage(New Uri("pack://application:,,,/Resources/" & ImageName & ".png"))
    End If
End Sub

The GetSortButton routine

Private Sub GetSortButton(Of T As DependencyObject)(dep As DependencyObject, Tag As String, ByRef out As DependencyObject)
    If dep IsNot Nothing Then
        If TypeOf dep Is Button AndAlso CType(dep, Button).Tag = Tag Then
            out = dep
        Else
            If VisualTreeHelper.GetChildrenCount(dep) > 0 Then
                For i As Integer = 0 To VisualTreeHelper.GetChildrenCount(dep) - 1
                    GetSortButton(Of T)(VisualTreeHelper.GetChild(dep, i), Tag, out)
                Next
            End If
        End If
    End If
End Sub

This routine was found elsewhere on StackOverflow in C#. I converted it to VB.

Private Function GetChildOfType(Of T As DependencyObject)(depObj As DependencyObject) As T
    If depObj Is Nothing Then
        Return Nothing
    End If

    For i As Integer = 0 To VisualTreeHelper.GetChildrenCount(depObj) - 1
        Dim child = VisualTreeHelper.GetChild(depObj, i)

        Dim result = If(TryCast(child, T), GetChildOfType(Of T)(child))
        If result IsNot Nothing Then
            Return result
        End If
    Next
    Return Nothing
End Function

You may have a better way. Please post if you do.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM