using System; using System.Collections.Generic; using System.Linq; using System.Reactive; using System.Reactive.Linq; using DynamicData; using NodeNetwork.ViewModels; using ReactiveUI; namespace NodeNetwork.Toolkit.NodeList { /// /// A viewmodel for a UI List component that contains NodeViewModels /// and can be used to let the user add new nodes to a network. /// public class NodeListViewModel : ReactiveObject { static NodeListViewModel() { NNViewRegistrar.AddRegistration(() => new NodeListView(), typeof(IViewFor)); } /// /// The formatting mode of the list. /// public enum DisplayMode { /// /// The nodes are displayed graphically in a grid. /// Tiles, /// /// The node names are displayed as text in a list. /// List } #region Title /// /// The string that is displayed at the top of the list /// public string Title { get => _title; set => this.RaiseAndSetIfChanged(ref _title, value); } private string _title; #endregion #region EmptyLabel /// /// The string that is displayed when VisibleNodes is empty. /// public string EmptyLabel { get => _emptyLabel; set => this.RaiseAndSetIfChanged(ref _emptyLabel, value); } private string _emptyLabel = ""; #endregion #region DisplayMode /// /// The way the list of available nodes is formatted. /// public DisplayMode Display { get => _display; set => this.RaiseAndSetIfChanged(ref _display, value); } private DisplayMode _display; #endregion #region NodeTemplates /// /// List of all the available nodes in the list. /// public ISourceList NodeTemplates { get; } = new SourceList(); #endregion #region VisibleNodes /// /// List of nodes that are actually visible in the list. /// This list is based on Nodes and SearchQuery. /// public IObservableList VisibleNodes { get; } #endregion #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 public NodeListViewModel() { Title = "Add node"; EmptyLabel = "No matching nodes found."; Display = DisplayMode.Tiles; var onQueryChanged = this.WhenAnyValue(vm => vm.SearchQuery) .Throttle(TimeSpan.FromMilliseconds(200), RxApp.MainThreadScheduler) .Publish(); onQueryChanged.Connect(); VisibleNodes = NodeTemplates.Connect() .AutoRefreshOnObservable(_ => onQueryChanged) .Transform(t => t.Instance) .AutoRefresh(node => node.Name) .Filter(n => (n.Name ?? "").ToUpper().Contains(SearchQuery?.ToUpper() ?? "")) .AsObservableList(); } /// /// Adds a new node type to the list. /// Every time a node is added to a network from this list, the factory function will be called to create a new instance of the viewmodel type. /// /// The subtype of NodeViewModel to add to the list. /// The factory function to create a new instance of T public void AddNodeType(Func factory) where T : NodeViewModel { NodeTemplates.Add(new NodeTemplate(factory)); } } }