<#
.SYNOPSIS
    Provides a collection of shared helper functions for manipulating WPF UI controls, handling asynchronous updates, and managing common UI interactions.
.DESCRIPTION
    This module contains a variety of reusable functions designed to support the FFU Builder UI. It includes utilities for managing ListView controls, such as sorting, reordering items, and handling 'Select All' functionality. It also provides thread-safe mechanisms for updating the UI from background tasks, wrappers for modern and classic file/folder dialogs, and generic functions for clearing UI content. These shared functions help to reduce code duplication and ensure consistent behavior across different parts of the application.
#>

# Function to update priorities sequentially in a ListView
function Update-ListViewPriorities {
    param(
        [Parameter(Mandatory)]
        [System.Windows.Controls.ListView]$ListView
    )

    $currentPriority = 1
    foreach ($item in $ListView.Items) {
        if ($null -ne $item -and $item.PSObject.Properties['Priority']) {
            $item.Priority = $currentPriority
            $currentPriority++
        }
    }
    $ListView.Items.Refresh()
    Request-ListViewColumnAutoResize -ListView $ListView
}

# Function to move selected item to the top
function Move-ListViewItemTop {
    param(
        [Parameter(Mandatory)]
        [System.Windows.Controls.ListView]$ListView
    )

    $selectedItem = $ListView.SelectedItem
    if ($null -eq $selectedItem) { return }

    $currentIndex = $ListView.Items.IndexOf($selectedItem)
    if ($currentIndex -gt 0) {
        $ListView.Items.RemoveAt($currentIndex)
        $ListView.Items.Insert(0, $selectedItem)
        $ListView.SelectedItem = $selectedItem
        Update-ListViewPriorities -ListView $ListView
    }
}

# Function to move selected item up one position
function Move-ListViewItemUp {
    param(
        [Parameter(Mandatory)]
        [System.Windows.Controls.ListView]$ListView
    )

    $selectedItem = $ListView.SelectedItem
    if ($null -eq $selectedItem) { return }

    $currentIndex = $ListView.Items.IndexOf($selectedItem)
    if ($currentIndex -gt 0) {
        $ListView.Items.RemoveAt($currentIndex)
        $ListView.Items.Insert($currentIndex - 1, $selectedItem)
        $ListView.SelectedItem = $selectedItem
        Update-ListViewPriorities -ListView $ListView
    }
}

# Function to move selected item down one position
function Move-ListViewItemDown {
    param(
        [Parameter(Mandatory)]
        [System.Windows.Controls.ListView]$ListView
    )

    $selectedItem = $ListView.SelectedItem
    if ($null -eq $selectedItem) { return }

    $currentIndex = $ListView.Items.IndexOf($selectedItem)
    if ($currentIndex -lt ($ListView.Items.Count - 1)) {
        $ListView.Items.RemoveAt($currentIndex)
        $ListView.Items.Insert($currentIndex + 1, $selectedItem)
        $ListView.SelectedItem = $selectedItem
        Update-ListViewPriorities -ListView $ListView
    }
}

# Function to move selected item to the bottom
function Move-ListViewItemBottom {
    param(
        [Parameter(Mandatory)]
        [System.Windows.Controls.ListView]$ListView
    )

    $selectedItem = $ListView.SelectedItem
    if ($null -eq $selectedItem) { return }

    $currentIndex = $ListView.Items.IndexOf($selectedItem)
    if ($currentIndex -lt ($ListView.Items.Count - 1)) {
        $ListView.Items.RemoveAt($currentIndex)
        $ListView.Items.Add($selectedItem)
        $ListView.SelectedItem = $selectedItem
        Update-ListViewPriorities -ListView $ListView
    }
}

# Function to update status of a specific item in a ListView
function Update-ListViewItemStatus {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [object]$WindowObject, 
        [Parameter(Mandatory)]
        [object]$ListView,     
        [Parameter(Mandatory)]
        [string]$IdentifierProperty, 
        [Parameter(Mandatory)]
        [string]$IdentifierValue,
        [Parameter(Mandatory)]
        [string]$StatusProperty,     
        [Parameter(Mandatory)]
        [string]$StatusValue
    )
    
    # Ensure we are in UI mode and objects are of correct WPF types
    if ($WindowObject -is [System.Windows.Window] -and $ListView -is [System.Windows.Controls.ListView]) {
        # Directly update UI elements as this function is now called on the UI thread
        try {
            # Determine which collection to search: ItemsSource (preferred) or Items.
            $collectionToSearch = $null
            if ($null -ne $ListView.ItemsSource) {
                $collectionToSearch = $ListView.ItemsSource
            }
            else {
                $collectionToSearch = $ListView.Items
            }

            $itemToUpdate = $collectionToSearch | Where-Object { $_.$IdentifierProperty -eq $IdentifierValue } | Select-Object -First 1
            if ($null -ne $itemToUpdate) {
                $itemToUpdate.$StatusProperty = $StatusValue
                $ListView.Items.Refresh() # Refresh the view to show the change
                Request-ListViewColumnAutoResize -ListView $ListView
            }
            else {
                # Log if item not found (for debugging)
                WriteLog "Update-ListViewItemStatus: Item with $IdentifierProperty '$IdentifierValue' not found in ListView."
            }
        }
        catch {
            WriteLog "Update-ListViewItemStatus: Error updating ListView: $($_.Exception.Message)"
        }
    }
    else {
        # Log if called in non-UI mode or with incorrect types (should not happen if Invoke-ParallelProcessing $isUiMode is correct)
        WriteLog "Update-ListViewItemStatus: Skipped UI update for $IdentifierValue due to non-UI mode or incorrect object types."
    }
}

# Function to update overall progress bar and status text label
function Update-OverallProgress {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [object]$WindowObject,
        [Parameter(Mandatory)]
        [int]$CompletedCount,
        [Parameter(Mandatory)]
        [int]$TotalCount,
        [Parameter(Mandatory)]
        [string]$StatusText,
        [Parameter(Mandatory)] 
        [string]$ProgressBarName,
        [Parameter(Mandatory)]
        [string]$StatusLabelName
    )

    # Ensure we are in UI mode and WindowObject is of correct WPF type
    if ($WindowObject -is [System.Windows.Window]) {
        # Directly update UI elements as this function is now called on the UI thread
        try {
            # Find controls by name using the $WindowObject
            $pb = $WindowObject.FindName($ProgressBarName)
            $lbl = $WindowObject.FindName($StatusLabelName)

            if ($null -eq $pb) {
                WriteLog "Update-OverallProgress: ProgressBar '$ProgressBarName' not found."
                return
            }
            if ($null -eq $lbl) {
                WriteLog "Update-OverallProgress: StatusLabel '$StatusLabelName' not found."
                return
            }

            # Update the progress bar
            if ($TotalCount -gt 0) {
                $percentComplete = ($CompletedCount / $TotalCount) * 100
                $pb.Value = $percentComplete
            }
            else {
                $pb.Value = 0 
            }
            
            # Update the status label
            $lbl.Text = $StatusText
            
        }
        catch {
            WriteLog "Update-OverallProgress: Error updating progress: $($_.Exception.Message)"
        }
    } 
    else {
        # Log if called in non-UI mode or with incorrect types
        WriteLog "Update-OverallProgress: Skipped UI update ($StatusText) due to non-UI mode or incorrect WindowObject type."
    }
}

# Helper function to enqueue progress updates to the UI thread
function Invoke-ProgressUpdate {
    param(
        [Parameter(Mandatory)]
        [System.Collections.Concurrent.ConcurrentQueue[hashtable]]$ProgressQueue,
        [Parameter(Mandatory)]
        [string]$Identifier,
        [Parameter(Mandatory)]
        [string]$Status
    )
    $ProgressQueue.Enqueue(@{ Identifier = $Identifier; Status = $Status })
}

function Update-BitsPrioritySetting {
    param(
        [Parameter(Mandatory)]
        [pscustomobject]$State
    )

    $combo = $State.Controls.cmbBitsPriority
    if ($null -eq $combo) {
        WriteLog "BITS priority control not available; skipping priority update."
        return
    }

    $selectedPriority = $combo.SelectedItem
    if ([string]::IsNullOrWhiteSpace($selectedPriority)) {
        $selectedPriority = 'Normal'
    }

    try {
        Set-BitsTransferPriority -Priority $selectedPriority
        WriteLog "BITS transfer priority set to $selectedPriority."
    }
    catch {
        WriteLog "Failed to set BITS transfer priority: $($_.Exception.Message)"
    }
}

# Add a function to create a sortable list view
function Add-SortableColumn {
    param(
        [System.Windows.Controls.GridView]$gridView,
        [string]$header,
        [string]$binding,
        [int]$width = 'Auto',
        [bool]$isCheckbox = $false,
        [System.Windows.HorizontalAlignment]$headerHorizontalAlignment = [System.Windows.HorizontalAlignment]::Stretch
    )

    $column = New-Object System.Windows.Controls.GridViewColumn
    $commonPadding = New-Object System.Windows.Thickness(5, 2, 5, 2)

    $headerControl = New-Object System.Windows.Controls.GridViewColumnHeader
    $headerControl.Tag = $binding # Used for sorting

    if ($isCheckbox) {
        # Cell template for a column of checkboxes
        $cellTemplate = New-Object System.Windows.DataTemplate
        $gridFactory = New-Object System.Windows.FrameworkElementFactory([System.Windows.Controls.Grid])

        $checkBoxFactory = New-Object System.Windows.FrameworkElementFactory([System.Windows.Controls.CheckBox])
        $checkBoxFactory.SetBinding([System.Windows.Controls.CheckBox]::IsCheckedProperty, (New-Object System.Windows.Data.Binding("IsSelected")))
        $checkBoxFactory.SetValue([System.Windows.FrameworkElement]::HorizontalAlignmentProperty, [System.Windows.HorizontalAlignment]::Center)
        $checkBoxFactory.SetValue([System.Windows.FrameworkElement]::VerticalAlignmentProperty, [System.Windows.VerticalAlignment]::Center)

        $checkBoxFactory.AddHandler([System.Windows.Controls.CheckBox]::ClickEvent, [System.Windows.RoutedEventHandler] {
                param($eventSourceLocal, $eventArgsLocal)
            })
        $gridFactory.AppendChild($checkBoxFactory)
        $cellTemplate.VisualTree = $gridFactory
        $column.CellTemplate = $cellTemplate
    }
    else {
        # For regular text columns
        $headerControl.HorizontalContentAlignment = $headerHorizontalAlignment
        $headerControl.Content = $header

        $headerTextElementFactory = New-Object System.Windows.FrameworkElementFactory([System.Windows.Controls.TextBlock])
        $headerTextElementFactory.SetValue([System.Windows.Controls.TextBlock]::TextProperty, $header)
        $headerTextBlockPadding = New-Object System.Windows.Thickness($commonPadding.Left, $commonPadding.Top, $commonPadding.Right, $commonPadding.Bottom)
        $headerTextElementFactory.SetValue([System.Windows.Controls.TextBlock]::PaddingProperty, $headerTextBlockPadding)
        $headerTextElementFactory.SetValue([System.Windows.FrameworkElement]::VerticalAlignmentProperty, [System.Windows.VerticalAlignment]::Center)

        $headerDataTemplate = New-Object System.Windows.DataTemplate
        $headerDataTemplate.VisualTree = $headerTextElementFactory
        $headerControl.ContentTemplate = $headerDataTemplate

        $cellTemplate = New-Object System.Windows.DataTemplate
        $textBlockFactory = New-Object System.Windows.FrameworkElementFactory([System.Windows.Controls.TextBlock])
        $textBlockFactory.SetBinding([System.Windows.Controls.TextBlock]::TextProperty, (New-Object System.Windows.Data.Binding($binding)))
        # Adjust left padding to 0 for cell text to align with header text
        $cellTextBlockPadding = New-Object System.Windows.Thickness(0, $commonPadding.Top, $commonPadding.Right, $commonPadding.Bottom)
        $textBlockFactory.SetValue([System.Windows.Controls.TextBlock]::PaddingProperty, $cellTextBlockPadding)
        $textBlockFactory.SetValue([System.Windows.FrameworkElement]::HorizontalAlignmentProperty, [System.Windows.HorizontalAlignment]::Left)
        $textBlockFactory.SetValue([System.Windows.FrameworkElement]::VerticalAlignmentProperty, [System.Windows.VerticalAlignment]::Center)

        $cellTemplate.VisualTree = $textBlockFactory
        $column.CellTemplate = $cellTemplate
    }

    $column.Header = $headerControl

    if ($width -ne 'Auto') {
        $column.Width = $width
    }

    $gridView.Columns.Add($column)
}

# Function to add a selectable GridViewColumn with a "Select All" header CheckBox
function Add-SelectableGridViewColumn {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [System.Windows.Controls.ListView]$ListView,
        [Parameter(Mandatory)]
        [psobject]$State,
        [Parameter(Mandatory)]
        [string]$HeaderCheckBoxKeyName,
        [Parameter(Mandatory)]
        [double]$ColumnWidth,
        [string]$IsSelectedPropertyName = "IsSelected",
        [string]$IsSelectablePropertyName,
        [string]$HeaderToolTip = 'Select or clear all selectable rows.',
        [string]$ItemToolTip = 'Select this row.',
        [switch]$HeaderSelectionAffectsVisibleItemsOnly
    )

    # Ensure the ListView has a GridView
    if ($null -eq $ListView.View -or -not ($ListView.View -is [System.Windows.Controls.GridView])) {
        WriteLog "Add-SelectableGridViewColumn: ListView '$($ListView.Name)' does not have a GridView or View is null. Cannot add column."
        return
    }
    $gridView = $ListView.View

    # Create the "Select All" CheckBox for the header
    $headerCheckBox = New-Object System.Windows.Controls.CheckBox
    $headerCheckBox.HorizontalAlignment = [System.Windows.HorizontalAlignment]::Center
    $headerCheckBox.VerticalAlignment = [System.Windows.VerticalAlignment]::Center

    # Store header metadata, including whether select-all should only affect visible rows.
    $headerTagObject = [PSCustomObject]@{
        PropertyName                           = $IsSelectedPropertyName
        SelectablePropertyName                 = $IsSelectablePropertyName
        ListViewControl                        = $ListView
        HeaderSelectionAffectsVisibleItemsOnly = [bool]$HeaderSelectionAffectsVisibleItemsOnly
    }
    $headerCheckBox.Tag = $headerTagObject
    $headerCheckBox.ToolTip = $HeaderToolTip

    $headerCheckBox.Add_Checked({
            param($senderCheckBoxLocal, $eventArgsCheckedLocal)
            $tagData = $senderCheckBoxLocal.Tag
            $localPropertyName = $tagData.PropertyName
            $actualListView = $tagData.ListViewControl

            # Select either visible view items only (filtered scope) or the full backing list.
            $collectionToUpdate = @()
            if ($tagData.HeaderSelectionAffectsVisibleItemsOnly -and $null -ne $actualListView.ItemsSource) {
                $collectionView = [System.Windows.Data.CollectionViewSource]::GetDefaultView($actualListView.ItemsSource)
                if ($null -ne $collectionView) {
                    foreach ($visibleItem in $collectionView) {
                        $collectionToUpdate += $visibleItem
                    }
                }
            }
            elseif ($null -ne $actualListView.ItemsSource) {
                $collectionToUpdate = @($actualListView.ItemsSource)
            }
            elseif ($actualListView.HasItems) {
                $collectionToUpdate = @($actualListView.Items)
            }

            if ($collectionToUpdate.Count -gt 0) {
                foreach ($item in $collectionToUpdate) {
                    $selectablePropertyName = $tagData.SelectablePropertyName
                    if (-not [string]::IsNullOrWhiteSpace($selectablePropertyName) -and $null -ne $item.PSObject.Properties[$selectablePropertyName] -and -not [bool]$item.$selectablePropertyName) {
                        $item.$($localPropertyName) = $false
                        continue
                    }
                    $item.$($localPropertyName) = $true
                }
                $actualListView.Items.Refresh()
            }
        })

    $headerCheckBox.Add_Unchecked({
            param($senderCheckBoxLocal, $eventArgsUncheckedLocal)
            if ($senderCheckBoxLocal.IsChecked -eq $false) {
                $tagData = $senderCheckBoxLocal.Tag
                $localPropertyName = $tagData.PropertyName
                $actualListView = $tagData.ListViewControl 

                # Clear either visible view items only (filtered scope) or the full backing list.
                $collectionToUpdate = @()
                if ($tagData.HeaderSelectionAffectsVisibleItemsOnly -and $null -ne $actualListView.ItemsSource) {
                    $collectionView = [System.Windows.Data.CollectionViewSource]::GetDefaultView($actualListView.ItemsSource)
                    if ($null -ne $collectionView) {
                        foreach ($visibleItem in $collectionView) {
                            $collectionToUpdate += $visibleItem
                        }
                    }
                }
                elseif ($null -ne $actualListView.ItemsSource) {
                    $collectionToUpdate = @($actualListView.ItemsSource)
                }
                elseif ($actualListView.HasItems) {
                    $collectionToUpdate = @($actualListView.Items)
                }

                if ($collectionToUpdate.Count -gt 0) {
                    foreach ($item in $collectionToUpdate) { $item.$($localPropertyName) = $false }
                    $actualListView.Items.Refresh()
                }
            }
        })

    # Wrap the header checkbox in a stretched container so it centers the same way as row cells.
    # Apply a small left inset to mirror the Fluent ListViewItem content padding used by data rows.
    $headerBorder = New-Object System.Windows.Controls.Border
    $headerBorder.Padding = New-Object System.Windows.Thickness(12, 0, 0, 0)
    $headerBorder.HorizontalAlignment = [System.Windows.HorizontalAlignment]::Stretch
    $headerBorder.VerticalAlignment = [System.Windows.VerticalAlignment]::Stretch

    $headerGrid = New-Object System.Windows.Controls.Grid
    $headerGrid.HorizontalAlignment = [System.Windows.HorizontalAlignment]::Stretch
    $headerGrid.VerticalAlignment = [System.Windows.VerticalAlignment]::Stretch
    $headerGrid.Children.Add($headerCheckBox) | Out-Null
    $headerBorder.Child = $headerGrid

    # Use an explicit GridViewColumnHeader so we can remove the default header padding
    # and control the checkbox alignment explicitly.
    $selectableHeader = New-Object System.Windows.Controls.GridViewColumnHeader
    $selectableHeader.HorizontalContentAlignment = [System.Windows.HorizontalAlignment]::Stretch
    $selectableHeader.VerticalContentAlignment = [System.Windows.VerticalAlignment]::Stretch
    $selectableHeader.Padding = New-Object System.Windows.Thickness(0)
    $selectableHeader.Margin = New-Object System.Windows.Thickness(0)
    $selectableHeader.Content = $headerBorder

    $State.Controls[$HeaderCheckBoxKeyName] = $headerCheckBox
    WriteLog "Add-SelectableGridViewColumn: Stored header checkbox in State.Controls with key '$HeaderCheckBoxKeyName'."

    $selectableColumn = New-Object System.Windows.Controls.GridViewColumn
    $selectableColumn.Header = $selectableHeader
    $selectableColumn.Width = $ColumnWidth

    $cellTemplate = New-Object System.Windows.DataTemplate
    $borderFactory = New-Object System.Windows.FrameworkElementFactory([System.Windows.Controls.Border])
    $borderFactory.SetValue([System.Windows.FrameworkElement]::HorizontalAlignmentProperty, [System.Windows.HorizontalAlignment]::Stretch)
    $borderFactory.SetValue([System.Windows.FrameworkElement]::VerticalAlignmentProperty, [System.Windows.VerticalAlignment]::Stretch)

    $checkBoxFactory = New-Object System.Windows.FrameworkElementFactory([System.Windows.Controls.CheckBox])
    $checkBoxFactory.SetBinding([System.Windows.Controls.CheckBox]::IsCheckedProperty, (New-Object System.Windows.Data.Binding($IsSelectedPropertyName)))
    if (-not [string]::IsNullOrWhiteSpace($IsSelectablePropertyName)) {
        $checkBoxFactory.SetBinding([System.Windows.Controls.CheckBox]::IsEnabledProperty, (New-Object System.Windows.Data.Binding($IsSelectablePropertyName)))
    }
    $checkBoxFactory.SetValue([System.Windows.FrameworkElement]::HorizontalAlignmentProperty, [System.Windows.HorizontalAlignment]::Center)
    $checkBoxFactory.SetValue([System.Windows.FrameworkElement]::VerticalAlignmentProperty, [System.Windows.VerticalAlignment]::Center)
    $checkBoxFactory.SetValue([System.Windows.Controls.Control]::ToolTipProperty, $ItemToolTip)

    # MODIFICATION: Store the actual ListView object in the item checkbox's Tag
    $tagObject = [PSCustomObject]@{
        HeaderCheckboxKeyName = $HeaderCheckBoxKeyName
        ListViewControl       = $ListView 
    }
    $checkBoxFactory.SetValue([System.Windows.FrameworkElement]::TagProperty, $tagObject)

    $checkBoxFactory.AddHandler([System.Windows.Controls.CheckBox]::ClickEvent, [System.Windows.RoutedEventHandler] {
            param($eventSourceLocal, $eventArgsLocal)
            $itemCheckBox = $eventSourceLocal -as [System.Windows.Controls.CheckBox]
            $tagData = $itemCheckBox.Tag
            
            $headerCheckboxKeyFromTag = $tagData.HeaderCheckboxKeyName
            $targetListView = $tagData.ListViewControl

            # Get the state from the window tag
            $window = [System.Windows.Window]::GetWindow($targetListView)
            if ($null -eq $window -or $null -eq $window.Tag) {
                WriteLog "Add-SelectableGridViewColumn: ERROR - Could not get window or state from window tag."
                return
            }
            $localState = $window.Tag

            WriteLog "Add-SelectableGridViewColumn: Item Click. ListView: '$($targetListView.Name)', HeaderChkKey: '$headerCheckboxKeyFromTag'"

            $headerChk = $localState.Controls[$headerCheckboxKeyFromTag]
            if ($null -ne $headerChk) {
                Update-SelectAllHeaderCheckBoxState -ListView $targetListView -HeaderCheckBox $headerChk
            }
            else {
                WriteLog "Add-SelectableGridViewColumn: Error - Could not retrieve header checkbox from state with key '$headerCheckboxKeyFromTag'."
            }
        })

    $borderFactory.AppendChild($checkBoxFactory)
    $cellTemplate.VisualTree = $borderFactory
    $selectableColumn.CellTemplate = $cellTemplate

    $gridView.Columns.Insert(0, $selectableColumn)
    WriteLog "Add-SelectableGridViewColumn: Successfully added selectable column to '$($ListView.Name)'."
}

# Function to request a deferred GridView column auto-size pass
function Request-ListViewColumnAutoResize {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [System.Windows.Controls.ListView]$ListView
    )

    # Skip startup calls until the visual tree has finished loading.
    if (-not $ListView.IsLoaded) {
        return
    }

    # Ensure the ListView has registered auto-resize metadata before scheduling work.
    $autoResizeStateKey = 'FFU.ListViewColumnAutoResizeState'
    if (-not $ListView.Resources.Contains($autoResizeStateKey)) {
        return
    }

    if (-not ($ListView.View -is [System.Windows.Controls.GridView])) {
        return
    }

    $autoResizeState = $ListView.Resources[$autoResizeStateKey]
    if ($autoResizeState.ResizePending) {
        return
    }

    $autoResizeState.ResizePending = $true
    $previousErrorActionPreference = $ErrorActionPreference

    try {
        $ErrorActionPreference = 'Stop'

        $gridView = [System.Windows.Controls.GridView]$ListView.View
        $fixedColumnIndexes = @($autoResizeState.FixedColumnIndexes)
        $visibleItems = [System.Collections.Generic.List[object]]::new()

        if ($null -ne $ListView.ItemsSource) {
            $collectionView = [System.Windows.Data.CollectionViewSource]::GetDefaultView($ListView.ItemsSource)
            if ($null -ne $collectionView) {
                foreach ($visibleItem in $collectionView) {
                    $visibleItems.Add($visibleItem)
                }
            }
        }
        else {
            foreach ($visibleItem in $ListView.Items) {
                $visibleItems.Add($visibleItem)
            }
        }

        $ListView.UpdateLayout()

        $columnIndex = 0
        foreach ($column in $gridView.Columns) {
            if ($fixedColumnIndexes -contains $columnIndex) {
                $columnIndex++
                continue
            }

            if ($null -eq $column) {
                $columnIndex++
                continue
            }

            $headerText = ""
            $propertyName = $null

            if ($null -ne $column.DisplayMemberBinding -and $null -ne $column.DisplayMemberBinding.Path) {
                $propertyName = [string]$column.DisplayMemberBinding.Path.Path
            }

            if ($column.Header -is [System.Windows.Controls.GridViewColumnHeader]) {
                if (-not [string]::IsNullOrWhiteSpace([string]$column.Header.Content)) {
                    $headerText = [string]$column.Header.Content
                }
                if ([string]::IsNullOrWhiteSpace($propertyName) -and -not [string]::IsNullOrWhiteSpace([string]$column.Header.Tag)) {
                    $propertyName = [string]$column.Header.Tag
                }
            }
            elseif (-not [string]::IsNullOrWhiteSpace([string]$column.Header)) {
                $headerText = [string]$column.Header
            }

            if ([string]::IsNullOrWhiteSpace($headerText)) {
                $headerText = $propertyName
            }

            $headerMeasureBlock = New-Object System.Windows.Controls.TextBlock
            $headerMeasureBlock.Text = if ([string]::IsNullOrWhiteSpace($headerText)) { ' ' } else { $headerText }
            $headerMeasureBlock.FontFamily = $ListView.FontFamily
            $headerMeasureBlock.FontSize = $ListView.FontSize
            $headerMeasureBlock.FontStyle = $ListView.FontStyle
            $headerMeasureBlock.FontWeight = $ListView.FontWeight
            $headerMeasureBlock.FontStretch = $ListView.FontStretch
            $headerMeasureBlock.Measure([System.Windows.Size]::new([double]::PositiveInfinity, [double]::PositiveInfinity))

            $calculatedWidth = [math]::Ceiling($headerMeasureBlock.DesiredSize.Width + 36)

            foreach ($item in $visibleItems) {
                if ($null -eq $item -or [string]::IsNullOrWhiteSpace($propertyName)) {
                    continue
                }

                $itemProperty = $null
                if ($null -ne $item.PSObject -and $null -ne $item.PSObject.Properties) {
                    $matchedProperties = $item.PSObject.Properties.Match($propertyName)
                    if ($null -ne $matchedProperties -and $matchedProperties.Count -gt 0) {
                        $itemProperty = $matchedProperties | Select-Object -First 1
                    }
                }

                if ($null -eq $itemProperty) {
                    continue
                }

                $itemText = [string]$itemProperty.Value
                $extraWidth = 28

                switch ($propertyName) {
                    'Architecture' {
                        $extraWidth = 52
                    }
                    'AdditionalExitCodes' {
                        $extraWidth = 44
                    }
                    'IgnoreNonZeroExitCodes' {
                        $itemText = ' '
                        $extraWidth = 48
                    }
                    'IgnoreExitCodes' {
                        $extraWidth = 28
                    }
                }

                $itemMeasureBlock = New-Object System.Windows.Controls.TextBlock
                $itemMeasureBlock.Text = if ([string]::IsNullOrWhiteSpace($itemText)) { ' ' } else { $itemText }
                $itemMeasureBlock.FontFamily = $ListView.FontFamily
                $itemMeasureBlock.FontSize = $ListView.FontSize
                $itemMeasureBlock.FontStyle = $ListView.FontStyle
                $itemMeasureBlock.FontWeight = $ListView.FontWeight
                $itemMeasureBlock.FontStretch = $ListView.FontStretch
                $itemMeasureBlock.Measure([System.Windows.Size]::new([double]::PositiveInfinity, [double]::PositiveInfinity))

                $itemWidth = [math]::Ceiling($itemMeasureBlock.DesiredSize.Width + $extraWidth)
                if ($itemWidth -gt $calculatedWidth) {
                    $calculatedWidth = $itemWidth
                }
            }

            if ($propertyName -eq 'IgnoreNonZeroExitCodes') {
                $calculatedWidth = [math]::Max($calculatedWidth, 120)
            }

            $column.Width = [math]::Max($calculatedWidth, 40)
            $columnIndex++
        }
    }
    catch {
        WriteLog "Request-ListViewColumnAutoResize: Failed for '$($ListView.Name)': $($_.Exception.Message)"
        if (-not [string]::IsNullOrWhiteSpace($_.InvocationInfo.PositionMessage)) {
            WriteLog $_.InvocationInfo.PositionMessage
        }
        if (-not [string]::IsNullOrWhiteSpace($_.ScriptStackTrace)) {
            WriteLog $_.ScriptStackTrace
        }
    }
    finally {
        $ErrorActionPreference = $previousErrorActionPreference
        $autoResizeState.ResizePending = $false
    }
}

# Function to enable reusable auto-resizing for GridView-backed ListViews
function Enable-ListViewColumnAutoResize {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [System.Windows.Controls.ListView]$ListView,

        [int[]]$FixedColumnIndexes = @()
    )

    $autoResizeStateKey = 'FFU.ListViewColumnAutoResizeState'

    # Only GridView-backed lists can participate in column auto-sizing.
    if (-not ($ListView.View -is [System.Windows.Controls.GridView])) {
        WriteLog "Enable-ListViewColumnAutoResize: ListView '$($ListView.Name)' is not using a GridView. Skipping registration."
        return
    }

    if ($ListView.Resources.Contains($autoResizeStateKey)) {
        return
    }

    $autoResizeState = [PSCustomObject]@{
        FixedColumnIndexes = @($FixedColumnIndexes)
        ResizePending      = $false
    }
    $ListView.Resources[$autoResizeStateKey] = $autoResizeState
}

# Function to update the IsChecked state of a "Select All" header CheckBox
function Update-SelectAllHeaderCheckBoxState {
    param(
        [Parameter(Mandatory)]
        [System.Windows.Controls.ListView]$ListView,
        [Parameter(Mandatory)]
        [System.Windows.Controls.CheckBox]$HeaderCheckBox
    )

    # Determine whether this header should evaluate only visible (filtered) rows.
    $inspectVisibleItemsOnly = $false
    if ($null -ne $HeaderCheckBox.Tag -and $null -ne $HeaderCheckBox.Tag.PSObject.Properties['HeaderSelectionAffectsVisibleItemsOnly']) {
        $inspectVisibleItemsOnly = [bool]$HeaderCheckBox.Tag.HeaderSelectionAffectsVisibleItemsOnly
    }

    # Build the collection to inspect based on scope (visible view vs full source).
    $collectionToInspect = @()
    if ($inspectVisibleItemsOnly -and $null -ne $ListView.ItemsSource) {
        $collectionView = [System.Windows.Data.CollectionViewSource]::GetDefaultView($ListView.ItemsSource)
        if ($null -ne $collectionView) {
            foreach ($visibleItem in $collectionView) {
                $collectionToInspect += $visibleItem
            }
        }
    }
    elseif ($null -ne $ListView.ItemsSource) {
        $collectionToInspect = @($ListView.ItemsSource)
    }
    elseif ($ListView.HasItems) {
        $collectionToInspect = @($ListView.Items)
    }

    $selectablePropertyName = $null
    if ($null -ne $HeaderCheckBox.Tag -and $null -ne $HeaderCheckBox.Tag.PSObject.Properties['SelectablePropertyName']) {
        $selectablePropertyName = [string]$HeaderCheckBox.Tag.SelectablePropertyName
    }
    if (-not [string]::IsNullOrWhiteSpace($selectablePropertyName)) {
        $collectionToInspect = @($collectionToInspect | Where-Object { $null -eq $_.PSObject.Properties[$selectablePropertyName] -or [bool]$_.$selectablePropertyName })
    }

    # If no items are available in the selected scope, force unchecked.
    if ($collectionToInspect.Count -eq 0) {
        $HeaderCheckBox.IsChecked = $false
        return
    }

    $selectedCount = ($collectionToInspect | Where-Object { $_.IsSelected }).Count
    WriteLog "Update-SelectAllHeaderCheckBoxState: Selected count is $selectedCount for ListView '$($ListView.Name)'."
    $totalItemCount = $collectionToInspect.Count
    WriteLog "Update-SelectAllHeaderCheckBoxState: Total item count is $totalItemCount for ListView '$($ListView.Name)'."

    if ($totalItemCount -eq 0) {
        # Handle empty list case specifically
        $HeaderCheckBox.IsChecked = $false
    }
    elseif ($selectedCount -eq $totalItemCount) {
        $HeaderCheckBox.IsChecked = $true
    }
    elseif ($selectedCount -eq 0) {
        $HeaderCheckBox.IsChecked = $false
    }
    else {
        # Indeterminate state
        $HeaderCheckBox.IsChecked = $null
    }
}

# Function to toggle the IsSelected state of the currently selected ListView item
function Invoke-ListViewItemToggle {
    param(
        [Parameter(Mandatory)]
        [System.Windows.Controls.ListView]$ListView,
        [Parameter(Mandatory)]
        [psobject]$State,
        [Parameter(Mandatory)]
        [string]$HeaderCheckBoxKeyName
    )

    $selectedItem = $ListView.SelectedItem
    if ($null -eq $selectedItem) { return }
    if ($null -ne $selectedItem.PSObject.Properties['CanSelect'] -and -not [bool]$selectedItem.CanSelect) { return }

    # Store the current index to restore focus later
    $currentIndex = $ListView.SelectedIndex

    # Toggle the IsSelected property
    $selectedItem.IsSelected = -not $selectedItem.IsSelected
    $ListView.Items.Refresh()
    Request-ListViewColumnAutoResize -ListView $ListView

    # Update the 'Select All' header checkbox state
    $headerChk = $State.Controls[$HeaderCheckBoxKeyName]
    if ($null -ne $headerChk) {
        Update-SelectAllHeaderCheckBoxState -ListView $ListView -HeaderCheckBox $headerChk
    }

    # Restore selection and focus to the item that was just toggled
    if ($currentIndex -ge 0 -and $ListView.Items.Count -gt $currentIndex) {
        $ListView.SelectedIndex = $currentIndex
        
        # Ensure the UI is updated before trying to find the container
        $ListView.UpdateLayout()
        
        $listViewItem = $ListView.ItemContainerGenerator.ContainerFromIndex($currentIndex)
        if ($null -ne $listViewItem) {
            $listViewItem.Focus()
        }
    }
}

# Function to sort ListView items
function Invoke-ListViewSort {
    param(
        [System.Windows.Controls.ListView]$listView,
        [string]$property,
        [PSCustomObject]$State
    )

    # Preserve any active CollectionView filter so sorting does not reset a filtered driver model list
    $existingFilter = $null
    $existingCollectionView = $null
    if ($null -ne $listView.ItemsSource) {
        $existingCollectionView = [System.Windows.Data.CollectionViewSource]::GetDefaultView($listView.ItemsSource)
        if ($null -ne $existingCollectionView -and $existingCollectionView.Filter) {
            $existingFilter = $existingCollectionView.Filter
        }
    }

    # Ensure $State.Flags is a hashtable and contains the required sort properties
    if ($State.Flags -is [hashtable]) {
        if (-not $State.Flags.ContainsKey('lastSortProperty')) {
            $State.Flags['lastSortProperty'] = $null
        }
        if (-not $State.Flags.ContainsKey('lastSortAscending')) {
            $State.Flags['lastSortAscending'] = $true
        }
    }
    else {
        Write-Warning "Invoke-ListViewSort: \$State.Flags is not a hashtable or is null. Sort state may not work correctly."
        if ($null -eq $State.Flags) { $State.Flags = @{} }
        if ($State.Flags -is [hashtable]) {
            if (-not $State.Flags.ContainsKey('lastSortProperty')) { $State.Flags['lastSortProperty'] = $null }
            if (-not $State.Flags.ContainsKey('lastSortAscending')) { $State.Flags['lastSortAscending'] = $true }
        }
    }

    # Toggle sort direction if clicking the same column
    if ($State.Flags.lastSortProperty -eq $property) {
        $State.Flags.lastSortAscending = -not $State.Flags.lastSortAscending
    }
    else {
        $State.Flags.lastSortAscending = $true
    }
    $State.Flags.lastSortProperty = $property

    # Build the set of items to sort, enumerating the filtered view if a filter is active
    $currentItemsSource = $listView.ItemsSource
    $itemsToSort = @()
    if ($null -ne $existingCollectionView -and $null -ne $existingFilter) {
        foreach ($vItem in $existingCollectionView) {
            $itemsToSort += $vItem
        }
    }
    elseif ($null -ne $currentItemsSource) {
        $itemsToSort = @($currentItemsSource)
    }
    else {
        $itemsToSort = @($listView.Items)
    }

    if ($itemsToSort.Count -eq 0) {
        return
    }

    # Separate selected vs unselected for selected-first ordering
    $selectedItems = @($itemsToSort | Where-Object { $_.IsSelected })
    $unselectedItems = @($itemsToSort | Where-Object { -not $_.IsSelected })

    # Define primary sort criterion
    $primarySortDefinition = @{
        Expression = {
            $val = $_.$property
            if ($null -eq $val) { '' } else { $val }
        }
        Ascending  = $State.Flags.lastSortAscending
    }

    $sortCriteria = [System.Collections.Generic.List[hashtable]]::new()
    $sortCriteria.Add($primarySortDefinition)

    # Determine secondary sort property based on the ListView
    $secondarySortPropertyName = $null
    if ($listView.Name -eq 'lstDriverModels') {
        $secondarySortPropertyName = "Model"
    }
    elseif ($listView.Name -eq 'lstWingetResults') {
        $secondarySortPropertyName = "Name"
    }
    elseif ($listView.Name -eq 'lstAppsScriptVariables') {
        if ($property -eq "Key") {
            $secondarySortPropertyName = "Value"
        }
        elseif ($property -eq "Value") {
            $secondarySortPropertyName = "Key"
        }
        else {
            $secondarySortPropertyName = "Key"
        }
    }

    # Add secondary sort definition if applicable
    if ($null -ne $secondarySortPropertyName -and $property -ne $secondarySortPropertyName) {
        $itemsHaveSecondaryProperty = $false
        if ($unselectedItems.Count -gt 0) {
            if ($null -ne $unselectedItems[0].PSObject.Properties[$secondarySortPropertyName]) {
                $itemsHaveSecondaryProperty = $true
            }
        }
        elseif ($selectedItems.Count -gt 0) {
            if ($null -ne $selectedItems[0].PSObject.Properties[$secondarySortPropertyName]) {
                $itemsHaveSecondaryProperty = $true
            }
        }

        if ($itemsHaveSecondaryProperty) {
            $expressionScriptBlock = [scriptblock]::Create("`$_.$secondarySortPropertyName")
            $secondarySortDefinition = @{
                Expression = {
                    $val = Invoke-Command -ScriptBlock $expressionScriptBlock -ArgumentList $_
                    if ($null -eq $val) { '' } else { $val }
                }
                Ascending  = $true
            }
            $sortCriteria.Add($secondarySortDefinition)
        }
    }

    # Sort unselected items by combined sort criteria
    $sortedUnselected = $unselectedItems | Sort-Object -Property $sortCriteria.ToArray()
    if ($null -eq $sortedUnselected) {
        $sortedUnselected = @()
    }

    # Merge selected first, then sorted unselected
    $newSortedList = [System.Collections.Generic.List[object]]::new()
    $newSortedList.AddRange($selectedItems)
    $newSortedList.AddRange($sortedUnselected)

    # Reset ItemsSource and assign sorted list
    $listView.ItemsSource = $null
    $listView.ItemsSource = $newSortedList.ToArray()

    # Reapply preserved filter to maintain the user's filtered view
    if ($null -ne $existingFilter) {
        $newView = [System.Windows.Data.CollectionViewSource]::GetDefaultView($listView.ItemsSource)
        if ($null -ne $newView) {
            $newView.Filter = $existingFilter
        }
    }

    Request-ListViewColumnAutoResize -ListView $listView
}

# --------------------------------------------------------------------------
# SECTION: Modern Folder Picker
# --------------------------------------------------------------------------

# 1) Define a C# class that uses the correct GUIDs for IFileDialog, IFileOpenDialog, and FileOpenDialog,
#    while omitting conflicting "GetResults/GetSelectedItems" from IFileDialog.
if (-not ("ModernFolderBrowser" -as [type])) {
    $modernFolderBrowserCode = @"
    using System;
    using System.Runtime.InteropServices;

    public static class ModernFolderBrowser
    {
        // Flags for IFileDialog
        [Flags]
        private enum FileDialogOptions : uint
        
        {
            OverwritePrompt      = 0x00000002,
            StrictFileTypes      = 0x00000004,
            NoChangeDir          = 0x00000008,
            PickFolders          = 0x00000020,
            ForceFileSystem      = 0x00000040,
            AllNonStorageItems   = 0x00000080,
            NoValidate           = 0x00000100,
            AllowMultiSelect     = 0x00000200,
            PathMustExist        = 0x00000800,
            FileMustExist        = 0x00001000,
            CreatePrompt         = 0x00002000,
            ShareAware           = 0x00004000,
            NoReadOnlyReturn     = 0x00008000,
            NoTestFileCreate     = 0x00010000,
            DontAddToRecent      = 0x02000000,
            ForceShowHidden      = 0x10000000
        }

        // IFileDialog (GUID from Windows SDK)
        //  - Omitting GetResults / GetSelectedItems to avoid overshadow.
        [ComImport]
        [Guid("42F85136-DB7E-439C-85F1-E4075D135FC8")]
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        private interface IFileDialog
        {
            [PreserveSig]
            int Show(IntPtr parent);

            void SetFileTypes(uint cFileTypes, IntPtr rgFilterSpec);
            void SetFileTypeIndex(uint iFileType);
            void GetFileTypeIndex(out uint piFileType);
            void Advise(IntPtr pfde, out uint pdwCookie);
            void Unadvise(uint dwCookie);
            void SetOptions(FileDialogOptions fos);
            void GetOptions(out FileDialogOptions pfos);
            void SetDefaultFolder(IShellItem psi);
            void SetFolder(IShellItem psi);
            void GetFolder(out IShellItem ppsi);
            void GetCurrentSelection(out IShellItem ppsi);
            void SetFileName([MarshalAs(UnmanagedType.LPWStr)] string pszName);
            void GetFileName(out IntPtr pszName);
            void SetTitle([MarshalAs(UnmanagedType.LPWStr)] string pszTitle);
            void SetOkButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string pszText);
            void SetFileNameLabel([MarshalAs(UnmanagedType.LPWStr)] string pszLabel);
            void GetResult(out IShellItem ppsi);
            void AddPlace(IShellItem psi, int fdap);
            void SetDefaultExtension([MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension);
            void Close(int hr);
            void SetClientGuid(ref Guid guid);
            void ClearClientData();
            void SetFilter(IntPtr pFilter);

            // NOTE: We intentionally do NOT define GetResults and GetSelectedItems here,
            // because they cause overshadow warnings in IFileOpenDialog.
        }

        // IFileOpenDialog extends IFileDialog by adding 2 new methods with the same name,
        // which otherwise cause overshadow warnings. We'll define them only here.
        [ComImport]
        [Guid("D57C7288-D4AD-4768-BE02-9D969532D960")]
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        private interface IFileOpenDialog : IFileDialog
        {
            // These two come after the parent's vtable:
            void GetResults(out IntPtr ppenum);
            void GetSelectedItems(out IntPtr ppsai);
        }

        // The coclass for creating an IFileOpenDialog
        [ComImport]
        [Guid("DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7")]
        private class FileOpenDialog
        {
        }

        // IShellItem
        [ComImport]
        [Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE")]
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        private interface IShellItem
        {
            void BindToHandler(IntPtr pbc, ref Guid bhid, ref Guid riid, out IntPtr ppv);
            void GetParent(out IShellItem ppsi);
            void GetDisplayName(uint sigdnName, out IntPtr ppszName);
            void GetAttributes(uint sfgaoMask, out uint psfgaoAttribs);
            void Compare(IShellItem psi, uint hint, out int piOrder);
        }

        [DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        private static extern int SHCreateItemFromParsingName([MarshalAs(UnmanagedType.LPWStr)] string pszPath, IntPtr pbc, ref Guid riid, [MarshalAs(UnmanagedType.Interface, IidParameterIndex = 2)] out IShellItem ppv);

        private const uint SIGDN_FILESYSPATH = 0x80058000;
        private static readonly Guid IID_IShellItem = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE");

        public static string ShowDialog(string title, IntPtr parentHandle, string initialDirectory)
        {
            // Create COM dialog instance
            IFileOpenDialog dialog = (IFileOpenDialog)(new FileOpenDialog());

            // Get current options
            FileDialogOptions opts;
            dialog.GetOptions(out opts);

            // Add flags for picking folders
            opts |= FileDialogOptions.PickFolders | FileDialogOptions.PathMustExist | FileDialogOptions.ForceFileSystem;
            dialog.SetOptions(opts);

            // Set initial directory if provided
            if (!string.IsNullOrEmpty(initialDirectory))
            {
                try
                {
                    Guid iid = IID_IShellItem; // Create a local copy to pass by ref
                    if (SHCreateItemFromParsingName(initialDirectory, IntPtr.Zero, ref iid, out IShellItem initialFolder) == 0)
                    {
                        dialog.SetFolder(initialFolder);
                        Marshal.ReleaseComObject(initialFolder);
                    }
                }
                catch
                {
                    // Ignore errors in setting initial directory (e.g., path doesn't exist)
                }
            }

            // Set title
            if (!string.IsNullOrEmpty(title))
            {
                dialog.SetTitle(title);
            }

            // Show the dialog
            int hr = dialog.Show(parentHandle);
            // 0 = S_OK. 1 or 0x800704C7 often means user canceled. Return null if so.
            if (hr != 0)
            {
                if ((uint)hr == 0x800704C7 || hr == 1)
                {
                    return null; // Canceled
                }
                else
                {
                    Marshal.ThrowExceptionForHR(hr);
                }
            }

            // Retrieve the selection (IShellItem)
            IShellItem shellItem;
            dialog.GetResult(out shellItem);
            if (shellItem == null) return null;

            // Convert to file system path
            IntPtr pszPath = IntPtr.Zero;
            shellItem.GetDisplayName(SIGDN_FILESYSPATH, out pszPath);
            if (pszPath == IntPtr.Zero) return null;

            string folderPath = Marshal.PtrToStringAuto(pszPath);
            Marshal.FreeCoTaskMem(pszPath);

            return folderPath;
        }
    }
"@
    Add-Type -TypeDefinition $modernFolderBrowserCode -Language CSharp
}

# 2) Define a PowerShell function that invokes our C# wrapper
function Show-ModernFolderPicker {
    param(
        [string]$Title = "Select a folder",
        [string]$InitialDirectory
    )
    # For a simple test, pass IntPtr.Zero as the parent window handle
    return [ModernFolderBrowser]::ShowDialog($Title, [IntPtr]::Zero, $InitialDirectory)
}

function Invoke-BrowseAction {
    param(
        [Parameter(Mandatory = $true)]
        [ValidateSet('Folder', 'OpenFile', 'SaveFile')]
        [string]$Type,

        [string]$Title,
        [string]$Filter,
        [string]$InitialDirectory,
        [string]$FileName,
        [string]$DefaultExt,
        [switch]$AllowNewFile
    )

    switch ($Type) {
        'Folder' {
            return Show-ModernFolderPicker -Title $Title -InitialDirectory $InitialDirectory
        }
        'OpenFile' {
            $dialog = New-Object Microsoft.Win32.OpenFileDialog
            $dialog.Title = $Title
            if (-not [string]::IsNullOrWhiteSpace($Filter)) { $dialog.Filter = $Filter }
            if ($AllowNewFile) { $dialog.CheckFileExists = $false }
            if (-not [string]::IsNullOrWhiteSpace($InitialDirectory)) {
                $dialog.InitialDirectory = $InitialDirectory
            }
            if (-not [string]::IsNullOrWhiteSpace($FileName)) {
                $dialog.FileName = $FileName
            }
            if ($dialog.ShowDialog()) {
                return $dialog.FileName
            }
        }
        'SaveFile' {
            $dialog = New-Object Microsoft.Win32.SaveFileDialog
            $dialog.Title = $Title
            if (-not [string]::IsNullOrWhiteSpace($Filter)) { $dialog.Filter = $Filter }
            if ($AllowNewFile) { $dialog.CheckFileExists = $false } # This property is obsolete but used in existing code.
            if (-not [string]::IsNullOrWhiteSpace($InitialDirectory)) {
                $dialog.InitialDirectory = $InitialDirectory
            }
            if (-not [string]::IsNullOrWhiteSpace($FileName)) {
                $dialog.FileName = $FileName
            }
            if (-not [string]::IsNullOrWhiteSpace($DefaultExt)) {
                $dialog.DefaultExt = $DefaultExt
            }
            if ($dialog.ShowDialog()) {
                return $dialog.FileName
            }
        }
    }
    return $null
}

function Clear-ListViewContent {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [psobject]$State,

        [Parameter(Mandatory = $true)]
        [System.Windows.Controls.ListView]$ListViewControl,

        [Parameter(Mandatory = $true)]
        [string]$ConfirmationTitle,

        [Parameter(Mandatory = $true)]
        [string]$ConfirmationMessage,
        
        [Parameter(Mandatory = $false)]
        [System.Collections.IList]$BackingDataList,

        [Parameter(Mandatory = $false)]
        [string]$StatusMessage,

        [Parameter(Mandatory = $false)]
        [System.Windows.Controls.TextBox[]]$TextBoxesToClear,

        [Parameter(Mandatory = $false)]
        [scriptblock]$PostClearAction
    )

    $result = [System.Windows.MessageBox]::Show($ConfirmationMessage, $ConfirmationTitle, [System.Windows.MessageBoxButton]::YesNo, [System.Windows.MessageBoxImage]::Question)
    if ($result -ne [System.Windows.MessageBoxResult]::Yes) {
        return
    }

    try {
        # If a backing data list is provided, clear it and rebind. This is the preferred method.
        if ($null -ne $BackingDataList) {
            $BackingDataList.Clear()
            $ListViewControl.ItemsSource = $BackingDataList.ToArray()
        }
        # If no backing list, determine how to clear the control.
        else {
            # If ItemsSource is in use, the only valid way to clear is to set it to null or an empty collection.
            if ($null -ne $ListViewControl.ItemsSource) {
                $ListViewControl.ItemsSource = $null
            }
            # If ItemsSource is NOT in use, we can safely clear the Items collection directly (for BYO Apps).
            elseif ($null -ne $ListViewControl.Items) {
                $ListViewControl.Items.Clear()
            }
        }
        
        $ListViewControl.Items.Refresh()
        Request-ListViewColumnAutoResize -ListView $ListViewControl

        # Clear any specified textboxes
        if ($null -ne $TextBoxesToClear) {
            foreach ($textBox in $TextBoxesToClear) {
                $textBox.Clear()
            }
        }

        # Update the status message if provided
        if (-not [string]::IsNullOrWhiteSpace($StatusMessage) -and $null -ne $State.Controls.txtStatus) {
            $State.Controls.txtStatus.Text = $StatusMessage
        }

        # Execute any post-clear custom actions. The scriptblock will have access to the $State and $ListViewControl variables from this function's scope.
        if ($null -ne $PostClearAction) {
            & $PostClearAction
        }
    }
    catch {
        WriteLog "Error in Clear-ListViewContent for $($ListViewControl.Name): $($_.Exception.Message)"
        [System.Windows.MessageBox]::Show("An error occurred while clearing the list: $($_.Exception.Message)", "Error", "OK", "Error")
    }
}

Export-ModuleMember -Function *