Files
2026-04-17 14:55:32 -04:00

9.7 KiB
Raw Permalink Blame History

source_files, generated_at, model, schema_version, sha256
source_files generated_at model schema_version sha256
DataPRO/Modules/Groups/GroupList/ViewModel/GroupListViewModel.cs
2026-04-16T04:47:12.822358+00:00 Qwen/Qwen3-Coder-Next-FP8 1 efb48e4bf6e2c1c7

ViewModel

Documentation: GroupListViewModel


1. Purpose

GroupListViewModel is the core view model for the Group List UI module. It manages the display, filtering, sorting, selection, and lifecycle of IGroup entities within the application. It acts as the intermediary between the IGroupListView view and the underlying group data model (Group), handling user interactions (e.g., double-click to edit, filtering/sorting), coordinating background operations (e.g., loading test setup lists), and publishing/subscribing to domain events via IEventAggregator. It supports both single- and multi-select group operations and integrates with the Prism region management and Unity DI container.


2. Public Interface

Constructors

  • GroupListViewModel(IGroupListView view, IRegionManager regionManager, IEventAggregator eventAggregator, IUnityContainer unityContainer)
    Initializes the view model. Sets up the view binding, event subscriptions (e.g., RaiseNotification, BusyIndicatorChangeNotification), and initializes SelectedGroupItems as an ObservableCollection<IGroup>.

Public Methods

  • void ClearAllFilters()
    Clears all per-field filter terms stored in _filterByField.

  • void MouseDoubleClick(int index)
    If a single group is selected and index is valid, publishes a GroupListEditGroupEvent with the selected groups Id.

  • void Filter(string term)
    Sets CurrentSearchTerm to term, then re-applies sorting (which triggers filtering and re-sorting of Groups).

  • IGroup GetGroup(int? id, bool updateTags = true)
    Returns the group with the given id (if id >= 0). If updateTags is true, updates the global tag cache before fetching. Returns a new empty Group() if not found.

  • IGroup GetGroup(string displayName)
    Returns the non-embedded group matching displayName, preferring non-embedded over embedded groups (for backward compatibility with pre-2.0 group types). Returns null if none found.

  • IGroup[] GetGroups(int[] ids)
    Returns an array of groups whose Ids are in ids, preserving order only in that groups not in ids are removed (i.e., order is not guaranteed to match ids order).

  • IGroup[] GetAllGroups()
    Returns all groups (via Group.GetAllGroups()), unfiltered and unsorted.

  • void DeleteGroups(int[] ids)
    Deletes groups with given ids. For each group, nullifies StaticGroupId on all related embedded groups, deletes the group, updates AllGroups, and re-applies filters. Publishes errors via PageErrorEvent.

  • IGroup CreateGroup()
    Returns a new unsaved Group(true) (likely a new transient instance).

  • IGroup CreateGroup(SqlDataReader, List<string>, List<int>)
    Constructs a Group from a data reader and hardware/test setup lists.

  • IGroup CreateGroup(IGroupDbRecord, List<string>, List<int>)
    Constructs a Group from a database record and hardware/test setup lists.

  • IGroup CreateGroup(List<string>)
    Constructs a new Group with the given includedHardwareStringList.

  • void Filter(object tag, string term)
    Parses tag as a GroupFields enum value; if successful, stores term in _filterByField[tag], sets _sortField, and calls Filter(term).

  • void OnSetActive(object page, bool groupTile, object o)
    Sets Page, filters AllGroups to groups compatible with the current users role/tags, and either calls GetTestSetupListsAsync() (if groupTile == true) or Sort().

  • private void GetTestSetupListsAsync()
    Runs asynchronously: sets app status to busy, iterates over AllGroups in parallel to call g.SetTestSetupLists(), then re-sorts on the UI thread.

  • void Unset()
    Clears AllGroups, Groups, filters, and publishes ListViewStatusEvent with status Unloaded.

  • void Sort(object o, bool bColumnClick)
    Sorts AllGroups by GroupFields (parsed from o), applies CurrentSearchTerm and per-field filters (GroupFilter), and sets Groups. Updates sort direction on column click.

  • void Cleanup() / Task CleanupAsync() / void Initialize() / Task InitializeAsync() / void Activated()
    No-op stubs; likely required by Prism or custom interfaces but not implemented.

Public Properties

  • IGroupListView View Bound view instance.
  • InteractionRequest<Notification> NotificationRequest For displaying notification popups.
  • InteractionRequest<Confirmation> ConfirmationRequest For confirmation dialogs.
  • event PropertyChangedEventHandler PropertyChanged Implements INotifyPropertyChanged.
  • ObservableCollection<IGroup> SelectedGroupItems Tracks selected groups; raises GroupListGroupSelectedEvent on change.
  • IGroup[] Groups Currently displayed (filtered + sorted) groups.
  • bool IsBusy Bound to busy indicator; updated via OnBusyIndicatorNotification.
  • bool IsMenuIncluded / bool IsNavigationIncluded UI toggle flags.
  • string ListViewId "GroupListView"; used for event scoping.
  • int SelectedGroupIndex Index of selected group in Groups; default -1.

Private Properties (used in logic)

  • _filterByField: Dictionary<GroupFields, string> Per-field filter terms.
  • CurrentSearchTerm: string Global search term.
  • _sortField: GroupFields Current sort field (default LastModified).
  • _sortAscending: bool Sort direction (default false = descending).
  • _comparer: GroupComparer Comparison logic for sorting.

3. Invariants

  • Groups is always a filtered and sorted subset of AllGroups.
  • AllGroups is always filtered by user role and tag compatibility (via currentUser.TagCompatible(@group.TagIDs)).
  • SelectedGroupItems is an ObservableCollection; changes trigger GroupListGroupSelectedEvent.
  • _filterByField stores per-field filter terms; CurrentSearchTerm is a global term applied in Sort.
  • Groups is sorted by _sortField in _sortAscending order using GroupComparer.
  • IsBusy is updated via BusyIndicatorChangeNotification event (thread-safe subscription on PublisherThread).
  • SelectedGroupItems.CollectionChanged handler skips updates during flagged "updating" states (via DTS.Common.Enums.SelectedItemsStatus.GetUpdating).

4. Dependencies

Imports / Dependencies Used

  • Prism: IEventAggregator, IRegionManager, Unity, Prism.Events, Prism.Regions, Prism.Interactivity.
  • DTS Common Libraries:
    • DTS.Common.Events.* (e.g., RaiseNotification, BusyIndicatorChangeNotification, PageErrorEvent, AppStatusEvent, ProgressBarEvent, ListViewStatusEvent, GroupListEditGroupEvent, GroupListGroupSelectedEvent)
    • DTS.Common.Interface.Groups.* (IGroup, IGroupListView, IGroupListViewModel)
    • DTS.Common.Enums.Groups.GroupList.* (GroupFields, ListViewStatusArg)
    • DTS.Common.Storage.* (DbOperations)
    • DTS.Slice.Users.User
    • DTS.Common.Classes.Tags.TagsInstance
  • .NET: System.ComponentModel, System.Collections.ObjectModel, System.Threading.Tasks, System.Linq, System.Collections.Specialized, System.Windows, System.Data.SqlClient.SqlDataReader.

Dependencies on This Module

  • GroupListViewModel is exported via MEF ([PartCreationPolicy(CreationPolicy.Shared)]) and likely consumed by DI container resolution for IGroupListViewModel.
  • IGroupListView must be provided at construction (likely via Prism view injection).
  • Other modules subscribe to events it publishes: GroupListEditGroupEvent, GroupListGroupSelectedEvent, PageErrorEvent, ListViewStatusEvent.

5. Gotchas

  • Sorting logic comment: The Sort method contains commented-out logic suggesting a potential bug or inconsistency in handling already-sorted lists (especially for LastModified). This may cause unexpected sort direction toggling.
  • GetGroup(string displayName) behavior: Returns only non-embedded groups if any exist; otherwise returns null. This may hide embedded groups unexpectedly.
  • GetGroups(int[] ids) order: Output order is not guaranteed to match input ids order (uses Contains in reverse iteration).
  • SelectedGroupItems setter: Unsubscribes from CollectionChanged only if _selectedGroupItems was non-null before assignment. If SelectedGroupItems is set multiple times, old handlers may leak if not handled carefully.
  • OnSetActive filtering: Filtering by user role/tag compatibility happens only in OnSetActive, not in Filter or Sort. Thus, filtering/sorting operates on already-filtered AllGroups.
  • GetTestSetupListsAsync: Runs SetTestSetupLists() in parallel (AsParallel().ForAll), but UI thread re-sort is done via Dispatcher.Invoke. Potential for race conditions if SetTestSetupLists() modifies group state accessed during sort.
  • GroupFilter case sensitivity: Uses CompareOptions.OrdinalIgnoreCase for all fields, including LastModified (stringified) — may yield unexpected matches (e.g., "12" matches "12" but also "12" in "12/12/2023").
  • No validation on DeleteGroups: Does not check if groups are in use (e.g., by tests); relies on underlying Group.Delete(id) to handle errors (which are then published via PageErrorEvent).
  • IsDirty property: Declared but never set; always false.
  • Cleanup()/Initialize() stubs: All Initialize*, Cleanup*, and Activated() methods are empty — may indicate incomplete implementation or reliance on external lifecycle management.

None identified beyond those above.