我一直在为数据网格创建自己的类似Excel的自动筛选器。我希望能够重用代码。我已经完成它的功能,但是遇到了一个问题..请解释我所拥有的以及问题的出处
首先,我有一个带有数据网格和一些测试列的简单wpf表单,并制作了一个简单的testdatalist,并在XAML中将其添加为要绑定的collectionviewsource
-每个注释均经过编辑以仅提供所需的代码。 -
以下是XAML中的一些行
xmlns:local="clr-namespace:WPFFilterDesign"
<local:testDatalist x:Key="testdatalist"/>
<CollectionViewSource x:Key="cvstestdatalist" Source="{StaticResource testdatalist}"></CollectionViewSource>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Path=propTest}">
<DataGridTextColumn.HeaderStyle>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</DataGridTextColumn.HeaderStyle>
<DataGridTextColumn.Header>
<local:textFilterControl x:Name="testcol1" HeadingName="Test"/>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Path=propStatus}">
<DataGridTextColumn.HeaderStyle>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</DataGridTextColumn.HeaderStyle>
<DataGridTextColumn.Header>
<local:textFilterControl x:Name="testStatus" HeadingName="Status"/>
</DataGridTextColumn.Header>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
这里是..I后面的代码,我删减并简化了一些内容
public class testData
{
public string propTest { get; set; }
public string propStatus { get; set; }
public string propTest2 { get; set; }
}
public class testDatalist : ObservableCollection<testData>
{
// Creating the Tasks collection in this way enables data binding from XAML.
}
public partial class MainWindow : Window
{
public static CollectionViewSource CVS_DG { get; set; }
public MainWindow()
{
InitializeComponent();
//get a referenceto the collection
testDatalist _testdatalist = (testDatalist)this.Resources["testdatalist"];
CVS_DG = (CollectionViewSource)(this.Resources["cvstestdatalist"]);
//add some data
testData temp = new testData() ;
temp.propTest = "testasdfa";
temp.propStatus = "Sold";
temp.propTest2 = "sadfa";
_testdatalist.Add(temp);
_testdatalist.Add(new testData() { propTest = "test1", propStatus = "Active", propTest2 = "afsa" });
_testdatalist.Add(new testData() { propTest = "test8", propStatus = "Sold", propTest2 = "afdfsa" });
_testdatalist.Add(new testData() { propTest = "test6", propStatus = "Sold", propTest2 = "afdahhfsa" });
_testdatalist.Add(new testData() { propTest = "test4", propStatus = "Complete", propTest2 = "affjsa" });
_testdatalist.Add(new testData() { propTest = "test9", propStatus = "Canceled", propTest2 = "afytsa" });
_testdatalist.Add(new testData() { propTest = "test8", propStatus = "Sold", propTest2 = "afsfdgytresa" });
_testdatalist.Add(new testData() { propTest = "test2", propStatus = "Active", propTest2 = "afferg5463sa" });
_testdatalist.Add(new testData() { propTest = "test3", propStatus = "Canceled", propTest2 = "a699kljfsa" });
_testdatalist.Add(new testData() { propTest = "test7", propStatus = "Active", propTest2 = "afsgfha" });
_testdatalist.Add(new testData() { propTest = "test2", propStatus = "Canceled", propTest2 = "afsatryrwe-0" });
_testdatalist.Add(new testData() { propTest = "test9", propStatus = "Active", propTest2 = "afshghjaq21a" });
}
}
那东西很标准。但是在XAML中,我在datagrid中有三列,对于每一列,我都将其用户控件“ textFilterControl”引入
这是用户控件XAML
<UserControl x:Class="WPFFilterDesign.textFilterControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WPFFilterDesign"
mc:Ignorable="d"
d:DesignHeight="20" d:DesignWidth="60">
<Grid Margin="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="16"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding HeadingName}" />
<Button Grid.Column="1" x:Name="btnFilter" Margin="3,0,0,0" HorizontalAlignment="Right" ContextMenuService.IsEnabled="False" Click="btnFilter_Click">
<Image Name="filterImage" Source="Resources/filternotapplied.png" />
<Button.ContextMenu>
<ContextMenu Name="CtxMenuText" Closed="CtxMenuText_Closed" Opened="CtxMenuText_Opened">
<ContextMenu.Template>
<ControlTemplate>
<Border BorderBrush="Black" BorderThickness="1" Width="120" Height="180">
<Grid Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<ComboBox Name="Filter1Type" Grid.Row="0" HorizontalAlignment="Stretch" Margin="5,3,5,3" SelectedIndex="0">
<ComboBoxItem Content="Starts with"/>
<ComboBoxItem Content="Ends with"/>
<ComboBoxItem Content="Contains"/>
<ComboBoxItem Content="Does not contain"/>
<ComboBoxItem Content="Equals"/>
<ComboBoxItem Content="Does not equal"/>
</ComboBox>
<TextBox Name="Filter1Value" HorizontalAlignment="Stretch" Grid.Row="1" Margin="5,3,5,3" TextChanged="Filter1Value_TextChanged"/>
<ComboBox Name="FilterCombineOperator" Grid.Row="2" Width="60" HorizontalAlignment="Left" SelectedIndex="0" Margin="5,3,5,3">
<ComboBoxItem Content="Or"/>
<ComboBoxItem Content="And"/>
</ComboBox>
<ComboBox Name="Filter2Type" Grid.Row="3" HorizontalAlignment="Stretch" SelectedIndex="0" Margin="5,3,5,3" IsEnabled="False">
<ComboBoxItem Content="Starts with"/>
<ComboBoxItem Content="Ends with"/>
<ComboBoxItem Content="Contains"/>
<ComboBoxItem Content="Does not contain"/>
<ComboBoxItem Content="Equals"/>
<ComboBoxItem Content="Does not equal"/>
</ComboBox>
<TextBox Name="Filter2Value" HorizontalAlignment="Stretch" Grid.Row="4" Margin="5,3,5,3" IsEnabled="False"></TextBox>
<Button Name="btnApply" Content="Apply" Grid.Row="5" Width="50" Margin="5,3,5,5" HorizontalAlignment="Left" Click="btnApply_Click"></Button>
<Button Name="btnClear" Content="Clear" Grid.Row="5" Width="50" Margin="5,3,5,5" HorizontalAlignment="Right" Click="btnClear_Click"></Button>
<CheckBox Name="checkboxFiltered" Grid.Row="5" Visibility="Hidden"></CheckBox>
</Grid>
</Border>
</ControlTemplate>
</ContextMenu.Template>
</ContextMenu>
</Button.ContextMenu>
</Button>
</Grid>
</UserControl>
它只是在列标题上添加了一个过滤器按钮,该按钮使用上下文菜单实际显示过滤器选项。
看起来像这样
然后,用户控件的代码就是这个……只是其中一部分
public partial class textFilterControl : UserControl
{
//.....
private static int tempfilter1index;
private static string tempfilter1Value;
private static int tempOpteratorTypeIndex;
private static int tempfilter2Index;
private static string tempfilter2Value;
private static bool filterApplied = false;
private static string propname;
//https://social.msdn.microsoft.com/Forums/vstudio/en-US/d9a8921f-27a3-4e81-b7fd-d6cf1e23bbdf/usercontrol-passing-parameter?forum=wpf
public textFilterControl()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(Filter_Loaded);
}
void Filter_Loaded(object sender, RoutedEventArgs e)
{
}
private void btnFilter_Click(object sender, RoutedEventArgs e)
{
(sender as Button).ContextMenu.IsEnabled = true;
(sender as Button).ContextMenu.PlacementTarget = (sender as Button);
(sender as Button).ContextMenu.Placement = System.Windows.Controls.Primitives.PlacementMode.Bottom;
(sender as Button).ContextMenu.IsOpen = true;
}
private void btnApply_Click(object sender, RoutedEventArgs e)
{
//get current values
ComboBox filter1type = (ComboBox)CtxMenuText.Template.FindName("Filter1Type", CtxMenuText);
tempfilter1index = filter1type.SelectedIndex;
TextBox tboxFilter1 = (TextBox)CtxMenuText.Template.FindName("Filter1Value", CtxMenuText);
tempfilter1Value = tboxFilter1.Text;
ComboBox OperatorType = (ComboBox)CtxMenuText.Template.FindName("FilterCombineOperator", CtxMenuText);
tempOpteratorTypeIndex = OperatorType.SelectedIndex;
ComboBox filter2type = (ComboBox)CtxMenuText.Template.FindName("Filter2Type", CtxMenuText);
tempfilter2Index = filter2type.SelectedIndex;
TextBox tboxFilter2 = (TextBox)CtxMenuText.Template.FindName("Filter2Value", CtxMenuText);
tempfilter2Value = tboxFilter2.Text;
CheckBox isFiltered = (CheckBox)CtxMenuText.Template.FindName("checkboxFiltered", CtxMenuText);
if (isFiltered.IsChecked == true)
{
filterApplied = true;
}
else
{
filterApplied = false;
}
//change filter image if there is a filter to apply
//get specific image
var parent = this.Parent;
System.Windows.Controls.Primitives.DataGridColumnHeader column = (System.Windows.Controls.Primitives.DataGridColumnHeader)parent;
propname = column.Column.SortMemberPath;
//add filter
if(filterApplied == true)
{
MainWindow.CVS_DG.Filter -= new FilterEventHandler(CVS_DG_Filter);
MainWindow.CVS_DG.Filter += new FilterEventHandler(CVS_DG_Filter);
}
else
{
MainWindow.CVS_DG.Filter += new FilterEventHandler(CVS_DG_Filter);
filterApplied = true;
}
//close context menu
CtxMenuText.IsOpen = false;
}
private void CVS_DG_Filter(object sender, FilterEventArgs e)
{
dynamic src = e.Item;
var propertyInfo = src.GetType().GetProperty(propname);
var value = propertyInfo.GetValue(src, null);
if (value.Contains(tempfilter1Value))
{
}
else
{
e.Accepted = false;
}
}
}
在用户控件中,有一个Apply按钮,然后将其添加到该视图的过滤器中。现在,我的过滤器只是执行if包含,一旦我无法正常工作,请添加到过滤器中以匹配用户控件具有的所有选项。
一切正常,除了当我尝试过滤掉多列时。我相信这是因为即使是不同的实例,用户控件中的filter方法也具有相同的名称。验证我复制了用户控件并更改了它的名称,并且当我将过滤器应用于两列(每列使用控件控件的不同副本)时,过滤是否按预期工作。
我正在寻找有关如何使它工作的一些想法或建议。这里的想法是将过滤全部包含在用户控件中,这样我就可以在需要时重用它。我觉得我离我很近。请帮忙。