mogmo .NET

C#/XAML/VB6たまにC++についてメモ程度に書いていく。あくまで自分用。責任は取れません。

DataGrid の表示内容をTextBoxの入力内容でフィルタリングする

参考

WPF/XAML : DataGrid の表示内容を TextBox への入力内容でフィルタリングする - i++
上記サイトにお世話になりました。
ポイントは以下3つとのこと。

  • DataGrid の ItemsSource に CollectionViewSource.View を使う
  • CollectionViewSource.Filter にフィルタリング用の関数を登録する
  • TextBox の入力に変更がある度に CollectionViewSource.View.Refresh() を呼ぶ

サンプル

Model

名前と年齢の情報を持つPersonクラス

internal class Person
{
	public string Name { get; set; }
	public int Age { get; set; }
	public Person(string name, int age)
	{
		Name = name;
		Age = age;
	}
}

ViewModel

コンストラクタでFilterにフィルタリング用の関数を登録しています。

internal class MainWindowViewModel : INotifyPropertyChanged
{
	private string _quickFilter = "";
	private ObservableCollection<Person> _people = new ObservableCollection<Person>();
	private CollectionViewSource _peopleSource;

	public string QuickFilter { get => _quickFilter; set => this.SetQuickFilter(value); }
	public ObservableCollection<Person> People { get => _people; set => SetProperty(ref _people, value); }
	public CollectionViewSource PeopleSource { get => _peopleSource; set => SetProperty(ref _peopleSource, value); }


	public MainWindowViewModel()
	{
		this._people.Add(new Person($"田中0", 20));
		this._people.Add(new Person($"伊藤0", 21));
		this._people.Add(new Person($"佐藤0", 22));
		this._people.Add(new Person($"鈴木0", 27));
		this._people.Add(new Person($"田中1", 30));
		this._people.Add(new Person($"鈴木1", 43));
		this._people.Add(new Person($"田中2", 32));
		this._people.Add(new Person($"田中3", 38));

		_peopleSource = new CollectionViewSource();
		_peopleSource.Filter += PeopleSource_Filter;
		_peopleSource.Source = _people;
	}

	private void PeopleSource_Filter(object sender, FilterEventArgs e)
	{
		if (e.Item != null)
		{
			// テキストが空の時はフィルタリングなし
			if (String.IsNullOrEmpty(this.QuickFilter))
			{
				e.Accepted = true;
			}
			else
			{
				// 部分一致を受け入れる
				Person p = e.Item as Person;
				e.Accepted = p.Name.Contains(this.QuickFilter);
			}
		}
	}

	private void SetQuickFilter(string value)
	{
		if (this._quickFilter == value) return;
		this._quickFilter = value;
		OnPropertyChanged(nameof(this.QuickFilter));

		// filtering
		this.PeopleSource.View.Refresh();
	}

	#region INotifyPropertyChanged Support
	public event PropertyChangedEventHandler PropertyChanged;
	protected void OnPropertyChanged(string propertyName)
	{
		PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
	}

	protected virtual bool SetProperty<T>(ref T field, T value, [CallerMemberName]string propertyName = null)
	{
		if (Equals(field, value)) { return false; }
		field = value;
		this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
		return true;
	}
	#endregion INotifyPropertyChanged Support
}

XAML

メインウィンドウの中身を以下のように実装。

<Grid>
	<Grid.RowDefinitions>
		<RowDefinition Height="auto"/>
		<RowDefinition Height="*"/>
	</Grid.RowDefinitions>

	<TextBox Text="{Binding Path=QuickFilter}"/>
	<DataGrid Grid.Row="1" ItemsSource="{Binding Path=PeopleSource.View}" />
</Grid>