我正在尝试实现类似excel的列过滤和排序。为此,我使用了一个DataTemplate来定义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="ResourcesNoSortNoFilter.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>
结果很好。
我尝试使用VisualTreeHelper从列标题中找到图像,但标题属性是一个字符串。我也试过使用HeaderStyle和HeaderTemplate属性,但无济于事。
使用一个名为Snoop的WPF间谍程序,我可以看到那里的图像,但仍然不知道如何在代码中访问它。我需要在代码中访问它的原因是根据该列是否被排序和/或过滤来更改图像。(可以在XAML中完成吗?)好了,我知道怎么做了。这很可能不是正确的方法,但我找到了一个可行的方法。
给你一点关于这个过程的信息。
- 用户单击标题按钮。按钮标签属性被绑定到列标题。
- click事件处理程序实例化上下文菜单,并将其标签设置为等于按钮标签。
- 用户点击菜单项。
- 事件处理程序将上下文菜单标签属性和图像名称发送给查找按钮的例程,然后是按钮中的图像,并更改图像。
现在为代码
按钮点击事件处理程序:
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
菜单项单击事件处理器
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
SetColumnSortImage例程,它调用以下两个例程。
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
GetSortButton例程
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
这个例程可以在c#的StackOverflow中找到。我把它转换成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
你可能有更好的办法。