使用场景
在使用GridControl时,经常配套使用SearchPanel,有时需要自定义该区域,以显示期望的自定义内容。下面的例子自定义该区域,以显示查询过滤条目的数量。
样例代码
自定义 SearchPanelContentTemplate
<Style x:Key="{dxgt:TableViewThemeKey ResourceKey=SearchPanelContentTemplate, IsThemeIndependent=True}" TargetType="{x:Type ContentControl}">
<Setter Property="dx:FocusHelper2.Focusable" Value="False"/>
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid Background="{DynamicResource {dxgt:TableViewThemeKey ResourceKey=SearchPanelBackground}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<dxg:GridSearchControl x:Name="PART_SearchControl" View="{Binding Path=(dxg:GridControl.CurrentView), RelativeSource={RelativeSource TemplatedParent}}"
IsEditorTabStop="False" IsTabStop="False"
HorizontalAlignment="{Binding Path=(dxg:GridControl.CurrentView).SearchPanelHorizontalAlignment, RelativeSource={RelativeSource TemplatedParent}}"
SearchTextBoxMinWidth="{DynamicResource {dxgt:TableViewThemeKey ResourceKey=SearchPanelTextBoxMinWidth}}"
Visibility="{Binding Path=View.ActualShowSearchPanel, RelativeSource={RelativeSource Self}, Converter={dx:BooleanToVisibilityConverter}}"
Margin="{DynamicResource {dxgt:TableViewThemeKey ResourceKey=SearchPanelWithoutGroupedPanelMargin}}">
</dxg:GridSearchControl>
<TextBlock Margin="{DynamicResource {dxgt:TableViewThemeKey ResourceKey=SearchPanelWithoutGroupedPanelMargin}}" Grid.Row="1" Text="{Binding Path=(dxg:GridControl.CurrentView).SearchResultsCount, RelativeSource={RelativeSource TemplatedParent},StringFormat=Count search results: {0}}" />
</Grid>
<Border x:Name="PART_SearchPanelBorderBottom" BorderThickness="0,0,0,1" BorderBrush="{DynamicResource {dxgt:TableViewThemeKey ResourceKey=SearchPanelBorderBottomBrush}}">
<Border.Visibility>
<Binding Path="GroupPanelShown" ElementName="PART_SearchControl">
<Binding.Converter>
<dx:BoolToVisibilityInverseConverter/>
</Binding.Converter>
</Binding>
</Border.Visibility>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="GroupPanelShown" SourceName="PART_SearchControl" Value="True">
<Setter Property="Margin" Value="{DynamicResource {dxgt:TableViewThemeKey ResourceKey=SearchPanelWithGroupedPanelMargin}}" TargetName="PART_SearchControl"/>
</Trigger>
<DataTrigger Binding="{Binding Path=(dxg:GridControl.CurrentView).IsCompactMode, RelativeSource={RelativeSource TemplatedParent}}" Value="True">
<Setter TargetName="PART_SearchControl" Property="HorizontalAlignment" Value="Stretch" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=(dxg:GridControl.CurrentView).ActualShowCompactPanel, RelativeSource={RelativeSource TemplatedParent}}" Value="True">
<Setter TargetName="PART_SearchPanelBorderBottom" Property="Visibility" Value="Collapsed" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
MainWindow
<Window x:Class="WpfApp17.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp17"
xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors"
xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid"
xmlns:dxgt="http://schemas.devexpress.com/winfx/2008/xaml/grid/themekeys"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<local:ViewModel />
</Window.DataContext>
<Window.Resources>
<Style x:Key="{dxgt:TableViewThemeKey ResourceKey=SearchPanelContentTemplate, IsThemeIndependent=True}" TargetType="{x:Type ContentControl}">
<Setter Property="dx:FocusHelper2.Focusable" Value="False"/>
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid Background="{DynamicResource {dxgt:TableViewThemeKey ResourceKey=SearchPanelBackground}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<dxg:GridSearchControl x:Name="PART_SearchControl" View="{Binding Path=(dxg:GridControl.CurrentView), RelativeSource={RelativeSource TemplatedParent}}"
IsEditorTabStop="False" IsTabStop="False"
HorizontalAlignment="{Binding Path=(dxg:GridControl.CurrentView).SearchPanelHorizontalAlignment, RelativeSource={RelativeSource TemplatedParent}}"
SearchTextBoxMinWidth="{DynamicResource {dxgt:TableViewThemeKey ResourceKey=SearchPanelTextBoxMinWidth}}"
Visibility="{Binding Path=View.ActualShowSearchPanel, RelativeSource={RelativeSource Self}, Converter={dx:BooleanToVisibilityConverter}}"
Margin="{DynamicResource {dxgt:TableViewThemeKey ResourceKey=SearchPanelWithoutGroupedPanelMargin}}">
</dxg:GridSearchControl>
<TextBlock Margin="{DynamicResource {dxgt:TableViewThemeKey ResourceKey=SearchPanelWithoutGroupedPanelMargin}}" Grid.Row="1" Text="{Binding Path=(dxg:GridControl.CurrentView).SearchResultsCount, RelativeSource={RelativeSource TemplatedParent},StringFormat=Count search results: {0}}" />
</Grid>
<Border x:Name="PART_SearchPanelBorderBottom" BorderThickness="0,0,0,1" BorderBrush="{DynamicResource {dxgt:TableViewThemeKey ResourceKey=SearchPanelBorderBottomBrush}}">
<Border.Visibility>
<Binding Path="GroupPanelShown" ElementName="PART_SearchControl">
<Binding.Converter>
<dx:BoolToVisibilityInverseConverter/>
</Binding.Converter>
</Binding>
</Border.Visibility>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="GroupPanelShown" SourceName="PART_SearchControl" Value="True">
<Setter Property="Margin" Value="{DynamicResource {dxgt:TableViewThemeKey ResourceKey=SearchPanelWithGroupedPanelMargin}}" TargetName="PART_SearchControl"/>
</Trigger>
<DataTrigger Binding="{Binding Path=(dxg:GridControl.CurrentView).IsCompactMode, RelativeSource={RelativeSource TemplatedParent}}" Value="True">
<Setter TargetName="PART_SearchControl" Property="HorizontalAlignment" Value="Stretch" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=(dxg:GridControl.CurrentView).ActualShowCompactPanel, RelativeSource={RelativeSource TemplatedParent}}" Value="True">
<Setter TargetName="PART_SearchPanelBorderBottom" Property="Visibility" Value="Collapsed" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<dxg:GridControl ItemsSource="{Binding Items}">
<dxg:GridControl.Columns>
<dxg:GridColumn FieldName="Id" />
<dxg:GridColumn FieldName="Name" />
<dxg:GridColumn FieldName="Group" />
<dxg:GridColumn FieldName="IsSet" />
<dxg:GridColumn FieldName="Time" />
</dxg:GridControl.Columns>
<dxg:GridControl.View>
<local:TreeListViewEx ShowSearchPanelMode="Always" SearchPanelAllowFilter="True" SearchString="Name_1"
TreeDerivationMode="Selfreference"
KeyFieldName="Id"
ParentFieldName="ParentId"
ScrollBarAnnotationMode="SearchResult"
AutoExpandAllNodes="True"/>
</dxg:GridControl.View>
</dxg:GridControl>
</Grid>
</Window>
MainWindow.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using DevExpress.Xpf.Grid;
namespace WpfApp17 {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
}
}
public class TreeListViewEx : TreeListView {
public int SearchResultsCount {
get { return (int)GetValue(SearchResultsCountProperty); }
set { SetValue(SearchResultsCountProperty, value); }
}
public static readonly DependencyProperty SearchResultsCountProperty =
DependencyProperty.Register("SearchResultsCount", typeof(int), typeof(TreeListViewEx), new PropertyMetadata(0));
List<int> searchResults = new List<int>();
protected override void UpdateFilterGrid() {
base.UpdateFilterGrid();
searchResults.Clear();
var fitPredicate = CreateFilterFitPredicate();
if(fitPredicate == null) {
SearchResultsCount = 0;
return;
}
for(int i = 0; i < DataProviderBase.DataRowCount; i++)
if(fitPredicate(i))
searchResults.Add(i);
SearchResultsCount = searchResults.Count;
}
}
}
ViewModel.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WpfApp17 {
public class ViewModel {
ObservableCollection<Item> _items;
public IEnumerable<Item> Items { get { return _items; } }
public ViewModel() {
_items = new ObservableCollection<Item>();
for(int i = 0; i < 100; i++)
_items.Add(new Item(i));
}
}
public class Item : INotifyPropertyChanged {
public Item() { }
public Item(int id) : base() {
Id = id + 1;
ParentId = Id < 5 ? -1 : Id / 5;
Name = "Name_" + id;
Group = "Group_" + id % 10;
IsSet = id % 2 == 0;
Time = DateTime.Now.AddDays(-id);
}
int _id;
public int Id { get { return _id; } set { _id = value; OnPropertyChanged("Id"); } }
int _parentId;
public int ParentId { get { return _parentId; } set { _parentId = value; OnPropertyChanged("ParentId"); } }
string _name;
public string Name { get { return _name; } set { _name = value; OnPropertyChanged("Name"); } }
string _group;
public string Group { get { return _group; } set { _group = value; OnPropertyChanged("Group"); } }
bool _isSet;
public bool IsSet { get { return _isSet; } set { _isSet = value; OnPropertyChanged("IsSet"); } }
DateTime _time;
public DateTime Time { get { return _time; } set { _time = value; OnPropertyChanged("Time"); } }
void OnPropertyChanged(string propertyName) {
if(PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
}