using DynamicData;
using ReactiveUI;
using System;
using System.Linq;
using System.Reactive.Linq;
using System.Windows.Input;
namespace NodeNetwork.Toolkit.ContextMenu
{
///
/// A data type containing a command, parameter and display properties.
///
public class LabeledCommand : ReactiveObject
{
#region Label
///
/// The label that is displayed in the menu
///
public string Label
{
get => _label;
set => this.RaiseAndSetIfChanged(ref _label, value);
}
private string _label = "";
#endregion
#region Visible
///
/// Should the command be displayed in the menu?
///
public bool Visible
{
get => _visible;
set => this.RaiseAndSetIfChanged(ref _visible, value);
}
private bool _visible = true;
#endregion
#region Command
///
/// The command to be executed.
///
public ICommand Command
{
get => _command;
set => this.RaiseAndSetIfChanged(ref _command, value);
}
private ICommand _command = null;
#endregion
#region CommandParameter
///
/// The parameter to be passed to the command on execution.
///
public object CommandParameter
{
get => _commandParameter;
set => this.RaiseAndSetIfChanged(ref _commandParameter, value);
}
private object _commandParameter = null;
#endregion
}
///
/// A viewmodel for a context menu in which the entries can be filtered by the user based on a searchquery.
///
public class SearchableContextMenuViewModel : ReactiveObject
{
static SearchableContextMenuViewModel()
{
NNViewRegistrar.AddRegistration(() => new SearchableContextMenuView(), typeof(IViewFor));
}
///
/// List of all the available commands in the menu.
///
public ISourceList Commands { get; } = new SourceList();
///
/// List of commands that are actually visible in the menu.
/// This list is based on Commands and SearchQuery.
///
public IObservableList VisibleCommands { get; }
#region SearchQuery
///
/// The current search string that is used to filter Nodes into VisibleNodes.
///
public string SearchQuery
{
get => _searchQuery;
set => this.RaiseAndSetIfChanged(ref _searchQuery, value);
}
private string _searchQuery = "";
#endregion
#region MaxItemsDisplayed
///
/// Only the first MaxItemsDisplayed items from Commands that match the query are displayed.
///
public int MaxItemsDisplayed
{
get => _maxItemsDisplayed;
set => this.RaiseAndSetIfChanged(ref _maxItemsDisplayed, value);
}
private int _maxItemsDisplayed = int.MaxValue;
#endregion
public SearchableContextMenuViewModel()
{
var onQueryChanged =
this.WhenAnyValue(vm => vm.SearchQuery, vm => vm.MaxItemsDisplayed)
.Throttle(TimeSpan.FromMilliseconds(70), RxApp.MainThreadScheduler)
.Publish();
onQueryChanged.Connect();
VisibleCommands = Commands.Connect()
.AutoRefreshOnObservable(_ => onQueryChanged)
.AutoRefresh(cmd => cmd.Label)
.AutoRefresh(cmd => cmd.Visible)
.Filter(cmd => cmd.Visible && (cmd.Label ?? "").ToUpper().Contains(SearchQuery?.ToUpper() ?? ""))
.Top(MaxItemsDisplayed)
.AsObservableList();
}
}
}