Browse Source

Create FilterViewModel and move abstract filtering to it

pull/5991/head
Max Katz 5 years ago
parent
commit
81fd48a2f7
  1. 12
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlDetailsViewModel.cs
  2. 124
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/FilterViewModel.cs
  3. 83
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreePageViewModel.cs

12
src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlDetailsViewModel.cs

@ -357,17 +357,7 @@ namespace Avalonia.Diagnostics.ViewModels
private bool FilterProperty(object arg)
{
if (!string.IsNullOrWhiteSpace(TreePage.PropertyFilter) && arg is PropertyViewModel property)
{
if (TreePage.UseRegexFilter)
{
return TreePage.FilterRegex?.IsMatch(property.Name) ?? true;
}
return property.Name.IndexOf(TreePage.PropertyFilter, StringComparison.OrdinalIgnoreCase) != -1;
}
return true;
return !(arg is PropertyViewModel property) || TreePage.PropertiesFilter.Filter(property.Name);
}
private class PropertyComparer : IComparer<PropertyViewModel>

124
src/Avalonia.Diagnostics/Diagnostics/ViewModels/FilterViewModel.cs

@ -0,0 +1,124 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text.RegularExpressions;
namespace Avalonia.Diagnostics.ViewModels
{
internal class FilterViewModel : ViewModelBase, INotifyDataErrorInfo
{
private readonly Dictionary<string, string> _errors = new Dictionary<string, string>();
private string _propertyFilter = string.Empty;
private bool _useRegexFilter, _useCaseSensitiveFilter, _useWholeWordFilter;
private string _processedFilter;
private Regex _filterRegex;
public event EventHandler RefreshFilter;
public bool Filter(string input)
{
return _filterRegex?.IsMatch(input) ?? true;
}
private void UpdateFilterRegex()
{
void ClearError()
{
if (_errors.Remove(nameof(PropertyFilter)))
{
ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(nameof(PropertyFilter)));
}
}
_processedFilter = PropertyFilter.Trim();
try
{
var options = RegexOptions.Compiled;
var pattern = UseRegexFilter
? _processedFilter : Regex.Escape(_processedFilter);
if (!UseCaseSensitiveFilter)
{
options |= RegexOptions.IgnoreCase;
}
if (UseWholeWordFilter)
{
pattern = $"\\b(?:{pattern})\\b";
}
_filterRegex = new Regex(pattern, options);
ClearError();
}
catch (Exception exception)
{
_errors[nameof(PropertyFilter)] = exception.Message;
ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(nameof(PropertyFilter)));
}
}
public string PropertyFilter
{
get => _propertyFilter;
set
{
if (RaiseAndSetIfChanged(ref _propertyFilter, value))
{
UpdateFilterRegex();
RefreshFilter?.Invoke(this, EventArgs.Empty);
}
}
}
public bool UseRegexFilter
{
get => _useRegexFilter;
set
{
if (RaiseAndSetIfChanged(ref _useRegexFilter, value))
{
UpdateFilterRegex();
RefreshFilter?.Invoke(this, EventArgs.Empty);
}
}
}
public bool UseCaseSensitiveFilter
{
get => _useCaseSensitiveFilter;
set
{
if (RaiseAndSetIfChanged(ref _useCaseSensitiveFilter, value))
{
UpdateFilterRegex();
RefreshFilter?.Invoke(this, EventArgs.Empty);
}
}
}
public bool UseWholeWordFilter
{
get => _useWholeWordFilter;
set
{
if (RaiseAndSetIfChanged(ref _useWholeWordFilter, value))
{
UpdateFilterRegex();
RefreshFilter?.Invoke(this, EventArgs.Empty);
}
}
}
public IEnumerable GetErrors(string propertyName)
{
if (_errors.TryGetValue(propertyName, out var error))
{
yield return error;
}
}
public bool HasErrors => _errors.Count > 0;
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
}
}

83
src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreePageViewModel.cs

@ -1,29 +1,27 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text.RegularExpressions;
using Avalonia.Controls;
using Avalonia.VisualTree;
namespace Avalonia.Diagnostics.ViewModels
{
internal class TreePageViewModel : ViewModelBase, IDisposable, INotifyDataErrorInfo
internal class TreePageViewModel : ViewModelBase, IDisposable
{
private readonly Dictionary<string, string> _errors = new Dictionary<string, string>();
private TreeNode _selectedNode;
private ControlDetailsViewModel _details;
private string _propertyFilter = string.Empty;
private bool _useRegexFilter;
public TreePageViewModel(MainViewModel mainView, TreeNode[] nodes)
{
MainView = mainView;
Nodes = nodes;
PropertiesFilter = new FilterViewModel();
PropertiesFilter.RefreshFilter += (s, e) => Details?.PropertiesView.Refresh();
}
public MainViewModel MainView { get; }
public FilterViewModel PropertiesFilter { get; }
public TreeNode[] Nodes { get; protected set; }
public TreeNode SelectedNode
@ -61,63 +59,6 @@ namespace Avalonia.Diagnostics.ViewModels
}
}
public Regex FilterRegex { get; set; }
private void UpdateFilterRegex()
{
void ClearError()
{
if (_errors.Remove(nameof(PropertyFilter)))
{
ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(nameof(PropertyFilter)));
}
}
if (UseRegexFilter)
{
try
{
FilterRegex = new Regex(PropertyFilter, RegexOptions.Compiled);
ClearError();
}
catch (Exception exception)
{
_errors[nameof(PropertyFilter)] = exception.Message;
ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(nameof(PropertyFilter)));
}
}
else
{
ClearError();
}
}
public string PropertyFilter
{
get => _propertyFilter;
set
{
if (RaiseAndSetIfChanged(ref _propertyFilter, value))
{
UpdateFilterRegex();
Details.PropertiesView.Refresh();
}
}
}
public bool UseRegexFilter
{
get => _useRegexFilter;
set
{
if (RaiseAndSetIfChanged(ref _useRegexFilter, value))
{
UpdateFilterRegex();
Details.PropertiesView.Refresh();
}
}
}
public void Dispose()
{
foreach (var node in Nodes)
@ -194,17 +135,5 @@ namespace Avalonia.Diagnostics.ViewModels
return null;
}
public IEnumerable GetErrors(string propertyName)
{
if (_errors.TryGetValue(propertyName, out var error))
{
yield return error;
}
}
public bool HasErrors => _errors.Count > 0;
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
}
}

Loading…
Cancel
Save