多列上datagrid自动过滤的用户控件

时间:2018-09-07 12:59:07

标签: c# wpf user-controls autofilter

我一直在为数据网格创建自己的类似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>

它只是在列标题上添加了一个过滤器按钮,该按钮使用上下文菜单实际显示过滤器选项。

看起来像这样

enter image description here

然后,用户控件的代码就是这个……只是其中一部分

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方法也具有相同的名称。验证我复制了用户控件并更改了它的名称,并且当我将过滤器应用于两列(每列使用控件控件的不同副本)时,过滤是否按预期工作。

我正在寻找有关如何使它工作的一些想法或建议。这里的想法是将过滤全部包含在用户控件中,这样我就可以在需要时重用它。我觉得我离我很近。请帮忙。

0 个答案:

没有答案