Home > Net >  WPF DataGrid rows filtering using TextBox and DatePicker elements
WPF DataGrid rows filtering using TextBox and DatePicker elements

Time:10-27

I am currently developing my first WPF application. I am using .NET Framework 4.8. In my WPF application I use a DataGrid element. I define my DataGrid element like this:

<DataGrid IsReadOnly="True" HeadersVisibility="Column" AutoGenerateColumns="False" Grid.Row="1" Grid.Column="0" x:Name="MyDataGrid" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top">
    <DataGrid.Resources>
        <Style TargetType="{x:Type DataGridColumnHeader}">
            <Setter Property="Background" Value="Turquoise" />
            <Setter Property="FontWeight" Value="Bold" />
            <Setter Property="BorderThickness" Value="0,0,1,2" />
            <Setter Property="BorderBrush" Value="Black" />
        </Style>
    </DataGrid.Resources>
    <DataGrid.Columns>
        <DataGridTextColumn Header="id" Binding="{Binding id}" Visibility="Hidden" Width="*"/>
        <DataGridTextColumn Header="fileId" Binding="{Binding fileId}" Visibility="Hidden" Width="*"/>
        <DataGridTextColumn Header="val1" Binding="{Binding val1}" Width="*"/>
        <DataGridTextColumn Header="val2" Binding="{Binding val2, StringFormat=\{0:dd.MM.yy\}}" Width="*"/>
        <DataGridTextColumn Header="val3" Binding="{Binding val3, StringFormat=\{0:dd.MM.yy\}}" Width="*"/>
    </DataGrid.Columns>
</DataGrid>

Furthermore, I have included two Datepickers and a TextBox. I have defined these as follows:

<TextBox Grid.Row="0" IsReadOnly="False" Grid.Column="1"  Name="FilterVal1" TextChanged="FilterDataGrid"/>
<DatePicker Grid.Row="1" Grid.Column="1" Name="FilterVal2" SelectedDateChanged="FilterDataGrid"/>
<DatePicker Grid.Row="2" Grid.Column="1" Name="FilterVal3" SelectedDateChanged="FilterDataGrid"/>

In my FilterDataGrid method I now filter the rows of the DataGrid as follows:

private void FilterDataGridKampagnen(object sender, object e)
{
    using (var ctx = new myEntities())
    {
        var query = from k in ctx.MyTbl select k;
        var lstMyTbl = query.ToList();
        if(this.FilterVal1.Text.Trim().Length > 0)
        {
            lstMyTbl = lstMyTbl.Where(x => x.val1.ToLower().Contains(this.FilterVal1.Text.ToLower())).ToList();
        }

        if (FilterVal2.SelectedDate != null)
        {
            lstMyTbl = lstMyTbl.Where(x => x.val2 >= FilterVal2.SelectedDate).ToList();
        }

        if (FilterVal3.SelectedDate != null)
        {
            lstMyTbl = lstMyTbl.Where(x => x.val3 <= FilterVal3.SelectedDate).ToList();
        }

        this.MyDataGrid.ItemsSource = lstMyTbl;
    }
}

I would now like to know if this is the correct (recommended) way to implement filters for a DataGrid element? Especially on the reference that there should be an AND relation between the filters and in case of an empty filter it should not be considered at all.

CodePudding user response:

Thanks to mm8. The probably "recommended" solution here would be the implementation in the MVVM design pattern. I have modified my code according to the MVVM design pattern. My DataGrid element looks like this (Important here is the binding of the ItemSource to ListData. ListData is a list in the ViewModel according to the MVVM design pattern.):

<DataGrid ItemsSource="{Binding ListData}" IsReadOnly="True" HeadersVisibility="Column" AutoGenerateColumns="False" Grid.Row="1" Grid.Column="0" x:Name="DataGridKampagnen" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top">
    <DataGrid.Resources>
        <Style TargetType="{x:Type DataGridColumnHeader}">
            <Setter Property="Background" Value="Turquoise" />
            <Setter Property="FontWeight" Value="Bold" />
            <Setter Property="BorderThickness" Value="0,0,1,2" />
            <Setter Property="BorderBrush" Value="Black" />
        </Style>
    </DataGrid.Resources>
    <DataGrid.Columns>
        <DataGridTextColumn Header="id" Binding="{Binding id}" Visibility="Hidden" Width="*"/>
        <DataGridTextColumn Header="fileId" Binding="{Binding fileId}" Visibility="Hidden" Width="*"/>
        <DataGridTextColumn Header="val1" Binding="{Binding val1}" Width="*"/>
        <DataGridTextColumn Header="val2" Binding="{Binding val2, StringFormat=\{0:dd.MM.yy\}}" Width="*"/>
        <DataGridTextColumn Header="val3" Binding="{Binding val3, StringFormat=\{0:dd.MM.yy\}}" Width="*"/>
    </DataGrid.Columns>
</DataGrid>

My two datepickers and my textbox look like this:

<TextBox Grid.Row="0" IsReadOnly="False" Grid.Column="1"  Name="FilterVal1" Style="{StaticResource FilterInput}" Text="{Binding Val1, UpdateSourceTrigger=PropertyChanged}"/>
<DatePicker Grid.Row="1" Grid.Column="1" Name="FilterVal2" Style="{StaticResource FilterInput}" SelectedDate="{Binding Val2}"/>
<DatePicker Grid.Row="2" Grid.Column="1" Name="FilterVal3" Style="{StaticResource FilterInput}" SelectedDate="{Binding Val3}"/>

My method which provides the data for binding to ListData looks like this:

private List<MyTbl> GetMyTblLst()
{
    using (var ctx = new myEntities())
    {
        var query = from k in ctx.MyTbl select k;
        var lstMyTbl = query.ToList();
        if(Val1.Trim().Length > 0)
        {
            lstMyTbl = lstMyTbl.Where(x => x.val1.ToLower().Contains(Val1.ToLower())).ToList();
        }

        if (Val2 != null)
        {
            lstMyTbl = lstMyTbl.Where(x => x.val2 >= Val2).ToList();
        }

        if (Val3 != null)
        {
            lstMyTbl = lstMyTbl.Where(x => x.val3 <= Val3).ToList();
        }

        return lstMyTbl;
    }
}

The binding to ListData is made like this:

public List<MyTbl> ListData => GetMyTblLst();

This approach works and is a very clean and reusable way to solve the problem.

  • Related