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

11 KiB
Raw Permalink Blame History

source_files, generated_at, model, schema_version, sha256
source_files generated_at model schema_version sha256
DataPRO/Modules/Groups/GroupImport/ViewModel/GroupImportViewModel.cs
2026-04-16T04:45:51.906727+00:00 Qwen/Qwen3-Coder-Next-FP8 1 f514e88931e0b70e

GroupImportViewModel Documentation

1. Purpose

GroupImportViewModel is the central view model for the group and channel import functionality in the DTS application. It orchestrates the end-to-end workflow of importing data from .grp files—parsing file contents, validating sensor and field data, allowing user review and selection of groups/channels for import, and committing validated data to the database via background processing. It serves as the data context for three distinct views (IGroupImportOptionsView, IGroupImportPreviewView, IGroupImportImportView) and integrates with Prisms region management, event aggregation, and Unity DI container to coordinate UI state and external service calls.

2. Public Interface

Constructor

public GroupImportViewModel(
    IGroupImportOptionsView optionsView,
    IGroupImportPreviewView previewView,
    IGroupImportImportView importView,
    IRegionManager regionManager,
    IEventAggregator eventAggregator,
    IUnityContainer unityContainer)

Initializes the view model, assigns views and their DataContext, sets up interaction requests (NotificationRequest, ConfirmationRequest), and subscribes to RaiseNotification and BusyIndicatorChangeNotification events.

Methods

  • void ParseSourceFiles(string userTags)
    Reads and parses all .grp files listed in SourceFiles. For each file:

    • Extracts group name from file name (strips extension).
    • Assigns userTags to GroupTags and ImportingUserTags.
    • Parses each non-empty line using Parse() (supports escaped commas via parentheses).
    • Validates fields: expects 5 fields per line (SensorSerialNumber, DisplayName, ISOCode, Invert, FullScale).
    • Reports errors for missing sensors (unless empty), invalid invert/full-scale values, wrong field count, or empty files.
    • Populates Groups and calls ProcessChannels().
  • void Import()
    Starts the import process on a background thread via ThreadPool.QueueUserWorkItem(ImportFunc).

  • private void ImportFunc(object o)
    Background method that:

    • Fetches default channel settings via DbOperations.GetChannelSettingDefaults().
    • Updates UI progress state (ImportProgressValue, ImportProgressBarVisibility, ImportProgressColor, DisableUI).
    • Iterates over included groups and their channels:
      • Skips channels with critical errors (FileEmpty, InvalidSensorInput, SensorNotFound).
      • For non-critical errors, uses null for invalid FullScale or Invert.
      • Calls CreateGroup, AddChannel, and finally CommitGroups.
    • Restores UI state on completion (though commented-out lines suggest UI reset is incomplete).
  • void SetStatus(string message, Color color)
    Updates ImportProgressText, ImportProgressColor, ImportProgressBarVisibility (collapsed), and invokes EnableUI.

  • void Reset()
    Clears all imported data: SourceFiles, Channels, Groups, progress state, and resets ImportProgressValue to 0.

  • void CheckGroupName()
    Validates group names:

    • Flags groups with duplicate names in the import set.
    • Flags groups whose name already exists in the application and Overwrite is false.
    • Sets GroupNameHasError = true on invalid groups.
  • private static string[] Parse(string line)
    Parses a single .grp line, respecting parenthetical escaping (e.g., "this(,)is" → one field "this(,)is").

  • private void ProcessChannels()
    Flattens all channels from Groups into the Channels array.

  • void InvalidateChannels()
    Raises PropertyChanged for IncompleteChannels and CompleteChannels computed properties.

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

Properties

  • IGroupImportOptionsView ImportOptionsView, IGroupImportPreviewView ImportPreviewView, IGroupImportImportView ImportView
    References to the three associated views.

  • string[] SourceFiles
    Array of .grp file paths to parse.

  • GroupGRPImportGroup[] Groups
    Parsed groups with their channels and errors.

  • GroupGRPImportChannel[] Channels
    Flattened list of all channels from Groups.

  • GroupGRPImportChannel[] IncompleteChannels
    Channels in included groups that have non-recoverable errors (e.g., SensorNotFound, InvalidSensorInput). These will not be imported.

  • GroupGRPImportChannel[] CompleteChannels
    Channels in included groups that either have no errors or have recoverable errors (InvalidFullScaleInput, InvalidInvertInput). These will be imported (with null for invalid fields).

  • string ImportProgressText, Color ImportProgressColor, Visibility ImportProgressBarVisibility, double ImportProgressValue
    UI state for the import progress bar.

  • bool IsBusy
    Bound to busy indicator; set via OnBusyIndicatorNotification.

  • InteractionRequest<Notification> NotificationRequest, InteractionRequest<Confirmation> ConfirmationRequest
    Prism interaction requests for showing notifications and confirmation dialogs.

  • bool IsDirty
    Read-only; always false (never set to true in source).

  • bool IsMenuIncluded, bool IsNavigationIncluded
    UI state flags (bound to menu/navigation visibility); no logic sets them beyond property change notifications.

  • string HeaderInfo
    Returns "MainRegion".

Commands

  • DelegateCommand ImportBrowseCommand
    Opens a file dialog (OpenFileDialog) with Multiselect=true, Filter from StringResources.ImportFileFilter, sets SourceFiles, BrowseOk=true, and navigates to Steps.Preview via SwitchNavSteps.

Delegates (Settable Properties)

  • CheckGroupExistsDelegate CheckGroupExists
    Function to check if a group exists in the application.

  • CheckSensorExistsDelegate CheckSensorExists
    Function to check if a sensor exists.

  • CreateGroupDelegate CreateGroup
    Action to create a group.

  • AddChannelToGroupDelegate AddChannel
    Action to add a channel to a group.

  • CommitGroupsDelegate CommitGroups
    Action to commit groups to the database.

  • Disable_UIDelegate DisableUI, Enable_UIDelegate EnableUI
    Actions to disable/enable the UI during import.

  • SwitchNavStepsDelegate SwitchNavSteps
    Action to navigate between import steps (e.g., Steps.Preview).

  • FileUtils.LogDelegate Logger
    Optional logging delegate; invoked on exceptions.

3. Invariants

  • File Parsing: Each .grp line must contain 5 comma-separated fields (or be empty/whitespace). Lines with fewer or more fields are marked with InvalidSensorInput.
  • Sensor Validation: A channel is flagged SensorNotFound if CheckSensorExists is non-null, the sensor serial number is non-empty, and CheckSensorExists(sensorSerialNumber) returns false. Empty sensor serial numbers are allowed (per comment referencing FB13753).
  • Invert Field: Accepts "yes"/"no" (case-insensitive) or bool.TryParse-compatible strings. Invalid values trigger InvalidInvertInput.
  • FullScale Field: Must parse as double; otherwise, InvalidFullScaleInput.
  • Group Name Uniqueness: Within the import set, duplicate group names are flagged. Across the import set and application, group names must be unique unless Overwrite=true.
  • Import Progress State: During ImportFunc, ImportProgressBarVisibility is set to Visible, DisableUI is called, and progress is tracked. Completion logic is partially commented out, so UI may not fully reset.
  • Channel Inclusion Logic: Only channels from groups where Included=true are considered for import. Channels with critical errors (FileEmpty, InvalidSensorInput, SensorNotFound) are skipped entirely; others may be imported with null for invalid fields.

4. Dependencies

Imports/References

  • DTS.Common:
    • Events (IEventAggregator, RaiseNotification, BusyIndicatorChangeNotification)
    • Utils (FileUtils.LogDelegate)
    • Classes.Groups (GroupGRPImportGroup, GroupGRPImportChannel, GroupGRPImportError)
    • Enums.Groups (GroupImportEnums.Steps, GroupGRPImportError.Errors)
    • Interface.Groups (IGroupImportOptionsView, IGroupImportPreviewView, IGroupImportImportView, IGroupImportViewModel)
    • Storage (DbOperations)
    • Interactivity (InteractionRequest<T>)
  • Prism:
    • Regions (IRegionManager)
    • Events (IEventAggregator)
    • DelegateCommand
  • Unity (IUnityContainer)
  • System.Windows (Visibility, Color)
  • System.Windows.Forms (OpenFileDialog)
  • StringResources (resource strings for UI messages)

Dependencies on External Services

  • DbOperations.GetChannelSettingDefaults() — for default channel settings.
  • CheckSensorExists, CheckGroupExists, CreateGroup, AddChannel, CommitGroups — injected delegates for database operations.
  • SwitchNavSteps — navigation delegate (likely from a parent view model or shell).

5. Gotchas

  • Incomplete UI Reset After Import: ImportFunc sets ImportProgressBarVisibility = Visibility.Visible and DisableUI, but the corresponding reset (Visibility.Collapsed, EnableUI) is commented out. This may leave the UI in a disabled state if import completes without error.
  • Empty Sensor Serial Numbers Are Allowed: Despite CheckSensorExists validation, empty serial numbers bypass the SensorNotFound check (FB13753).
  • Partial Error Tolerance: Channels with InvalidFullScaleInput or InvalidInvertInput are included in CompleteChannels and imported, but with null for the invalid field. This may cause downstream issues if the database or business logic does not handle null gracefully.
  • No Validation of Group Name Format: Only existence and duplication are checked; no format validation (e.g., reserved characters, length limits) is implemented.
  • Parse() Escaping Logic: Parentheses are treated as literal characters only when nested (via leftParenCount). A single ( or ) without matching pairs is still treated as a delimiter if not balanced.
  • IsDirty Never Set: The IsDirty property is declared but never updated, so it always returns false.
  • Initialize* and Cleanup* Methods Are No-ops: These likely exist to satisfy Prism interfaces but contain no logic.
  • Channels Property Triggers InvalidateChannels(): Setting Channels raises property change notifications for IncompleteChannels and CompleteChannels, but these are computed properties—modifying Channels directly may not reflect changes in the UI if Groups is not updated.
  • Thread Safety: ImportFunc runs on a background thread but updates UI properties directly (e.g., ImportProgressValue). While Prisms INotifyPropertyChanged may handle thread marshaling in some cases, this pattern is fragile and may cause cross-thread exceptions if the UI framework is strict.