简体   繁体   中英

How can I hide rows in a DataGrid?

I am trying to create a "notes" app using wpf mvvm. I have a MainWindow containing a DataGrid with data that is bound to an ObservableCollection. In MainWindowView I have a "Find" button which calls FindWindowDialog. In the FindWindowDialog in the textbox, I must enter the text that will be searched and click "Find", after which the DataGrid MainWindowView should hide those lines whose content does not contain the searched text. I don't really know how to do this, after 2 days of searching I decided to ask a question. I googled on this topic and I have a suggestion that I should delve into the messenger pattern and converters

MainWindow.xaml(View)

    <Window x:Class="NotesARK6.View.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:NotesARK6.View"
        xmlns:model="clr-namespace:NotesARK6.Model"
        xmlns:viewmodel="clr-namespace:NotesARK6.ViewModel"
        mc:Ignorable="d"
        Title="Notes" Height="450" Width="800"
        x:Name="_mainWindow"
        WindowStartupLocation="CenterScreen">

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="20" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="20" />
        </Grid.ColumnDefinitions>

        <Grid.RowDefinitions>
            <RowDefinition Height="20"/>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="10*"/>
            <RowDefinition Height="20"/>
        </Grid.RowDefinitions>

        <DataGrid ItemsSource="{Binding NotesCollection}" SelectedItem="{Binding SelectedNote}" IsReadOnly="True" AutoGenerateColumns="False" x:Name="DataGrid_Notes" Margin="5" Grid.Row="2" Grid.Column="1">
            <DataGrid.InputBindings>
                <MouseBinding Gesture="LeftDoubleClick" Command="{Binding EditNoteCommand}" CommandParameter="{Binding SelectedNote}" />
            </DataGrid.InputBindings>
            <DataGrid.Columns>
                <DataGridTextColumn Header="Name" Width="1*" Binding="{Binding Name}"/>
                <DataGridTextColumn Header="Content" Width="3*"  Binding="{Binding Content}"/>
            </DataGrid.Columns>
        </DataGrid>
        <ToolBar Grid.Row="1" Grid.Column="1" Margin="5">
            <Button Content="Create" Command="{Binding CreateNewNoteCommand}"/>
            <Separator />
            <Button Content="Delete" Command="{Binding DeleteNoteCommand}" CommandParameter="{Binding SelectedNote}"/>
            <Separator />
            <Button  Content="Find" Command="{Binding FindNoteCommand}"/>
        </ToolBar>
    </Grid>
</Window>

FindWindowDialog.xaml(view)

    <Window x:Class="NotesARK6.ViewModel.Dialogs.FindWindowDialog"
        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:NotesARK6.ViewModel.Dialogs"
        mc:Ignorable="d"
        Title="Find" Height="250" Width="400"
        WindowStartupLocation="CenterScreen"
        Topmost="True">
        
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="20"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="20"/>
        </Grid.ColumnDefinitions>

        <Grid.RowDefinitions>
            <RowDefinition Height="40"/>
            <RowDefinition Height="35"/>
            <RowDefinition Height="60"/>
            <RowDefinition Height="50"/>
            <RowDefinition Height="90"/>
        </Grid.RowDefinitions>

        <Grid Grid.Row="1" Grid.Column="1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>

            <CheckBox  IsChecked="{Binding SearchByName}" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="5" Content="Search by name" Grid.Column="0"></CheckBox>
            <CheckBox IsChecked="{Binding SearchByContent}" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="5" Content="Search by content" Grid.Column="1"></CheckBox>
        </Grid>
        
        <TextBox Text="{Binding SearchString}" Margin="5" Grid.Row="2" Grid.Column="1"/>
        <Button Command="{Binding FindNotesCommand}" Margin="5" Content="Find" Grid.Row="3" Grid.Column="1" /> 
    </Grid>
</Window>

FindWindowDialogViewModel.cs

public class FindWindowDialogViewModel : INotifyPropertyChanged
{
    private string searchString;
    private bool searchByName;
    private bool searchByContent;

    //Controll Commands
    public ControllComands FindNotesCommand { get; private set; }
    //Controll Commands 

    public FindWindowDialogViewModel()
    {
        FindNotesCommand = new ControllComands(FindNote);
    }

    public string SearchString 
    {
        get
        {
            return searchString;
        }
        set
        {
            searchString = value;
            OnPropertyChanged();
        }
    }

    public bool SearchByName
    {
        get
        {
            return searchByName;
        }
        set
        {
            searchByName = value;
            OnPropertyChanged("SearchByName");
        }
    }

    public bool SearchByContent
    {
        get
        {
            return searchByContent;
        }
        set
        {
            searchByContent = value;
            OnPropertyChanged("SearchByContent");
        }
    }

    public void FindNote()
    {
        MessageBox.Show(SearchByName.ToString() + " " + SearchByContent.ToString());
    }


    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged([CallerMemberName]string prop = "")
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(prop));
    }
}

How can I use the command contained in FindWindowDialogViewModel to hide rows in the DataGrid MainWindowView?

I would like something like this: (this is pseudocode)

public void FindNote()
    {
        foreach(var row in MainWindow.DataGrid.Rows)
        {
            string searchingText = FindNoteDialog.TextBox.Text;

            if (!row.Content.Contains(searchingText))
            {
                row.Visibillity = false;
            }
        }
    }

For this purpose collections provide filtering via their views (see Binding to collections and CollectionView API remarks to learn more).
Filtering using the collection's view has much better performance than hiding rows or removing items from the original collection.

To do so, you must get the ICollectionView of the source collection

Note.cs

class Note
{
  public string Summary { get; set; }
  public DateTime Timestamp { get; set; }
}

ViewModel.cs

class ViewModel : INotifyPropertyChanged
{
  public ObservableCollection<Note> Notes { get; }
  public string SearchKey { get; set; }
  public ICommand FilterNotesCommand => new RelayCommand(ExecuteFilterNotes);

  private void ExecuteFilterCommands(object commandParameter)
  {
    ICollectionView notesView = CollectionViewSource.GetDefaultView(this.Notes);
    notesView.Filter = item => (item as Note).Summary.Contains(this.SearchKey);
  }
}

MainWindow.xaml

<Window>
  <Window.DataContext>
    <ViewModel />
  </Window.DataContext>

  <StackPanel> 
    <TextBox Text="{Binding SearchKey}" />
    <Button Command="{Binding FilterNotesCommand}" Content="Filter Table" />
    <DataGrid ItemsSource="{Binding Notes}" />
  </StackPanel>
</Window>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM