web-dev-qa-db-fra.com

Filtrer un DataGrid dans WPF

Je charge une liste d'objets dans une grille de données avec ceci:

dataGrid1.Items.Add(model);

Les model deviennent des données d'une base de données. Il a une Id(int), Name(string) et Text(string)

Dans ma grille de données, je ne montre que le nom de la model. Comment puis-je filtrer la grille de données maintenant, lorsque je saisis quelque chose dans une zone de texte?

J'étais sur cette page: http://msdn.Microsoft.com/en-us/library/vstudio/ff407126(v=vs.100).aspx mais je ne comprends pas le code à partir de là et je ne peux pas expliquer comment je devrais transposer cela pour mon problème.

10
Karl_Schuhmann

il y a plusieurs façons de filtrer Collection

suggérons ceci est votre classe d'objet

public class Model
{
    public string Name
    {
        get;
        set;
    }
}

et votre collection ressemble à 

       var ObColl = new ObservableCollection<Model>();

        ObColl.Add(new Model() { Name = "John" });
        ObColl.Add(new Model() { Name = "Karl" });
        ObColl.Add(new Model() { Name = "Max" });
        ObColl.Add(new Model() { Name = "Mary" });

Voie 1 (Prédicat):

    public MainWindow()
    {
        InitializeComponent();

        // Collection which will take your ObservableCollection
        var _itemSourceList = new CollectionViewSource() { Source = ObColl };

        // ICollectionView the View/UI part 
        ICollectionView Itemlist = _itemSourceList.View;

        // your Filter
        var yourCostumFilter= new Predicate<object>(item => ((Model)item).Name.Contains("Max"));

        //now we add our Filter
        Itemlist.Filter = yourCostumFilter;

        dataGrid1.ItemsSource = Itemlist;
    }

Voie 2 (FilterEventHandler):

    public MainWindow()
    {
        InitializeComponent();

        // Collection which will take your Filter
        var _itemSourceList = new CollectionViewSource() { Source = ObColl };

       //now we add our Filter
       _itemSourceList.Filter += new FilterEventHandler(yourFilter);

        // ICollectionView the View/UI part 
        ICollectionView Itemlist = _itemSourceList.View;

        dataGrid1.ItemsSource = Itemlist;
    }

    private void yourFilter(object sender, FilterEventArgs e)
    {
        var obj = e.Item as Model;
        if (obj != null)
        {
            if (obj.Name.Contains("Max"))
                e.Accepted = true;
            else
                e.Accepted = false;
        }
    }

informations étendues à la voie 1

si vous avez besoin de plusieurs conditions ou d’un filtre complexe, vous pouvez ajouter une méthode à votre Predicat

    // your Filter
    var yourComplexFilter= new Predicate<object>(ComplexFilter);

    private bool ComplexFilter(object obj)
    {
        //your logic
    }
32
WiiMaxx

Ceci est une implémentation simple de l'utilisation de la propriété Filter de ICollectionView. Supposons que votre XAML contienne ceci:

<TextBox x:Name="SearchTextBox" />
<Button x:Name="SearchButton"
        Content="Search"
        Click="SearchButton_OnClick"
        Grid.Row="1" />
<DataGrid x:Name="MyDataGrid"
          Grid.Row="2">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Lorem ipsum column"
                            Binding="{Binding}" />
    </DataGrid.Columns>
</DataGrid>

Ensuite, dans le constructeur, vous pouvez obtenir la vue par défaut pour vos données, où vous pouvez définir le prédicat de filtre qui sera exécuté pour chaque élément de votre collection. Le CollectionView ne saura pas quand il doit mettre à jour la collection, vous devez donc appeler Actualiser lorsque l'utilisateur clique sur le bouton de recherche.

private ICollectionView defaultView;

public MainWindow()
{
    InitializeComponent();

    string[] items = new string[]
    {
        "Asdf",
        "qwer",
        "sdfg",
        "wert",
    };

    this.defaultView = CollectionViewSource.GetDefaultView(items);
    this.defaultView.Filter =
        w => ((string)w).Contains(SearchTextBox.Text);

    MyDataGrid.ItemsSource = this.defaultView;
}

private void SearchButton_OnClick(object sender, RoutedEventArgs e)
{
    this.defaultView.Refresh();
}

Vous trouverez une description plus détaillée de CollectionViews à cette adresse: http://wpftutorial.net/DataViews.html

5
Loránd Biró

@WiiMaxx, je ne peux pas commenter car pas assez de représentants. Je ferais un peu plus attention aux diffusions directes là-bas. Ils peuvent être lents pour une chose et pour une autre, si le même filtre était appliqué à une grille contenant différentes données de type complexe, vous auriez une exception InvalidCastException.

// your Filter
    var yourCostumFilter= new Predicate<object>(item =>
    {
        item = item as Model;
        return item == null || item.Name.Contains("Max");
    });

Cela ne cassera pas votre grille de données et ne filtrera pas les résultats si la conversion échoue. Moins d'impact pour vos utilisateurs si vous vous trompez de code. De plus, le filtre sera plus rapide du fait que l'opérateur "en tant que" n'effectue aucune contrainte de type explicite, contrairement à l'opération de diffusion directe.

3
steve

Vous pouvez utiliser le filtre d'affichage du journal afin de filtrer les lignes de la grille de données.

            DataView dv = datatable.DefaultView;

            StringBuilder sb = new StringBuilder();
            foreach (DataColumn column in dv.Table.Columns)
            {
                sb.AppendFormat("[{0}] Like '%{1}%' OR ", column.ColumnName, "FilterString");
            }
            sb.Remove(sb.Length - 3, 3);
            dv.RowFilter = sb.ToString();
            dgvReports.ItemsSource = dv;
            dgvReports.Items.Refresh();

Où "datatable" est la source de données donnée à votre grille de données et à l'aide du générateur de chaînes de caractères, vous construisez la requête de filtre, où "Chaîne de filtre" correspond au texte que vous souhaitez rechercher dans votre grille de données et définissez-le sur affichage de données, puis définissez la vue en tant que source d'éléments sur votre grille de données et le rafraîchir.

0
Joee

examinez DataBinding -> dans votre cas, n’ajoutez pas d’éléments à votre grille, mais définissez le

<Datagrid ItemsSource="{Binding MyCollectionOfModels}" />

ou 

dataGrid1.ItemsSource = this._myCollectionOfModels;

et si vous voulez une sorte de filtrage, de tri, de regroupement, regardez CollectionView

0
blindmeis