Member 14080213 Ответов: 0

Powershell winforms form load должен срабатывать дважды, чтобы получить данные для загрузки


Я полностью застрял на этом в течение последних двух недель. Я должен создать winform, который показывает каталоги и файлы в treeview. Я получил большую часть его работы (помимо загрузки поддельных узлов, чтобы показать знаки плюс/минус, но пока это нормально), но проблема, с которой я сталкиваюсь, заключается в том, что мне нужно запустить скрипт дважды, чтобы событие загрузки формы начало загружать данные в treeview. Как правило, я бы просто сделал addrange для treenodecollection, однако мой клиент хочет, чтобы размер папки и файлов отображался в заголовке. Вот что у меня есть:

<blockquote class="quote"><div class="op">Quote:</div>
[cmdletbinding()]
param(
    [string]$TargetPath = (get-item .).fullname
    )

#region Load Assemblies

[Void][System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[Void][System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[Void][System.Reflection.Assembly]::LoadWithPartialName("System.ServiceProcess")
[Void][System.Reflection.Assembly]::LoadWithPartialName("System.Design")
[void][System.Reflection.Assembly]::LoadWithPartialName('System.Collections.Generic')
[void][System.Reflection.Assembly]::LoadWithPartialName('System.Collections')
[void][System.Reflection.Assembly]::LoadWithPartialName('System.ComponentModel')
[void][System.Reflection.Assembly]::LoadWithPartialName('System.Text')
[void][System.Reflection.Assembly]::LoadWithPartialName('System.Data')
#endregion Load Assemblies


$ErrorActionPreference = 'continue' #'silentlycontinue'


#region Generated Form Objects

function InitializeComponent {

[System.Windows.Forms.Application]::EnableVisualStyles()
$MainForm = [System.Windows.Forms.Form]::new()
$TreeView = [System.Windows.Forms.Treeview]::new()
$RootNode = [System.Windows.Forms.TreeNode]::new()
$ContextMenu = [System.Windows.Forms.ContextMenuStrip]::new()
$PathMenuItem = [System.Windows.Forms.ToolStripMenuItem]::new()
$imagelist = [System.Windows.Forms.ImageList]::new()
$MainForm.SuspendLayout()

#Treeview
$TreeView.Location = '0, 0' 
$TreeView.Name = 'TreeView'
$TreeView.ImageIndex =  1
$TreeView.Size = '500, 900'#'296, 640'
$TreeView.Dock = 'Fill'
$TreeView.TabIndex = 3
$TreeView.SelectedImageIndex = 1
#$TreeView.Sorted = $true
$TreeView.AutoSize = $true
$TreeView.Font = 'Century Gothic, 12pt' #8.25pt'
#$TreeView.BorderStyle = 'None'
$TreeView.add_BeforeExpand($TreeView_BeforeExpand)
$TreeView.add_NodeMouseClick($TreeView_NodeMouseClick)
$TreeView.add_NodeMouseDoubleClick($TreeView_NodeMouseDoubleClick)

#RootNode
$RootNode.Name = 'Root'
$RootNode.Text = "Selected Path: $((Get-location).Path)"
$RootNode.Tag = "Directory"
[void]$TreeView.Nodes.Add($RootNode)

#ContextMenu
$ContextMenu.Name = "ContextMenu"
$ContextMenu.Size = '170, 26'
$ContextMenu.add_ItemClicked($ContextMenu_ItemClicked)
#[Void]$ContextMenu.Items.Add($PathMenuItem) 

#PathMenuItem
$PathMenuItem.Name = "PathMenuItem"
$PathMenuItem.Size = '169, 22'
$PathMenuItem.Text = "Change Path"
$PathMenuItem.Font = 'Century Gothic, 8.25pt'
$PathMenuItem.add_Click($PathMenuItem_Click)

#MainForm
$MainForm.ClientSize = '1440, 1000' #'1000, 800'
$MainForm.StartPosition = 'CenterScreen'
$MainForm.Text = "TreeView Disk Beta"
$MainForm.Padding = "0,0,0,0"
$MainForm.Font = [System.Drawing.Font]::new("Segoe UI",9,[System.Drawing.FontStyle]::Regular,[System.Drawing.GraphicsUnit]::Pixel) #'Segoe UI, 9pt'
$MainForm.FormBorderStyle = 'Sizable'
$MainForm.AutoSize = $true
$MainForm.AutoScaleDimensions = '6, 13'
#$MainForm.AutoScaleBaseSize = '6, 13'
$MainForm.AutoScaleMode = 'Font' #'Dpi'
$MainForm.Controls.Add($TreeView)
$MainForm.add_Load($MainForm_Load)
$MainForm.add_Load($Form_StateCorrection_Load)
#$MainForm.Add_Shown($MainForm_Shown)
$MainForm.add_FormClosing($Form_Cleanup_FormClosing)



#Save the initial state of the form
$InitialFormWindowState = $MainForm.WindowState
#$MainForm.ResumeLayout($false)
$MainForm.ResumeLayout()

}

 . InitializeComponent

#endregion Generated Form Objects

#region Functions

# Gets Size in human readable format for File and Folder Objects
function Get-FriendlySize {
    param($Bytes)
    $sizes='Bytes,KB,MB,GB,TB,PB,EB,ZB' -split ','
    for($i=0; ($Bytes -ge 1kb) -and 
        ($i -lt $sizes.Count); $i++) {$Bytes/=1kb}
        $N=2; if($i -eq 0) {$N=0}
            "{0:N$($N)} {1}" -f $Bytes, $sizes[$i]
} #Ref: https://martin77s.wordpress.com/2017/05/20/display-friendly-file-sizes-in-powershell

# Calls to change the path when right-click on Treeview
Function Change-TreePath {
$FolderBrowserDialog = [System.Windows.Forms.FolderBrowserDialog]::new()
$FolderBrowserDialog.ShowNewFolderButton = $false
$FolderBrowserDialog.Description = 'Select a Target Path'

if ($FolderBrowserDialog.ShowDialog() -eq 'OK') {
    $TargetPath = $FolderBrowserDialog.SelectedPath
    New-Variable -Name TargetPath -Value $TargetPath -Scope 1 -Force
    $TreeView.Nodes.Clear()
    $PathNode = [System.Windows.Forms.TreeNode]::new()
    $PathNode.Text = "Selected Path: $((Get-Item -Path $TargetPath).FullName)"
    [void]$TreeView.Nodes.Add($PathNode)
    & $MainForm_Load 
            }
    #[void]$FolderBrowserDialog.ShowDialog()
}

# Scriptblock for coloring nodes for Hidden Files and Folders
$ColorNode = {
    Foreach ($node in $TreeView.SelectedNode.Nodes) {
         if ($node.Tag -contains "hidden") {
            $node.ForeColor = [System.Drawing.Color]::OrangeRed 
        }
    }
}

Function InvokeAddNodes {
param($selectedNode, $IOPath)

gci -Path $IOPath -Force -ErrorAction SilentlyContinue | Foreach {
    if ($_ -is [System.IO.FileInfo]) {
    $ImageFiles = switch -Regex ($_.Extension) {
             "^\.ini|\.dll|\.sys"                         {5}
             "^\.exe|\.msi"                               {2}
             "^.jpg|\.png|\.bmp|\.ico|\.jpeg|\.fav|\.svg" {3}
             "^\.zip|\.rar|\.7z"                          {7}
             "\.txt|\.rtf|\.log|\.msg"                    {6}
             default                                      {0}
                }
    $subnode = [System.Windows.Forms.TreeNode]::new()
    $subnode.Name = $_.FullName
    $subnode.Text = & { ($_.Name + " " + (Get-FriendlySize -Bytes $_.Length) -as [string]) }
    $subnode.Tag = @(($_.Attributes).ToString().Split(",").Replace(" ", ""))
    $subnode.ImageIndex = $ImageFiles
    $subnode.SelectedImageIndex = $ImageFiles
                }
    if ($_ -is [System.IO.DirectoryInfo]) {
      $DirInfo =  $_ | gci -Force -ErrorAction SilentlyContinue | Measure-Object -Sum length -ErrorAction SilentlyContinue 
      $subnode = [System.Windows.Forms.TreeNode]::new()
      $subnode.Name = $_.FullName
      $subnode.Tag = @(($_.Attributes).ToString().Split(",").Replace(" ", ""))
      $subnode.ImageIndex = 1
      $subnode.SelectedImageIndex = 1
      if ($DirInfo.Count -gt 1) {     
            $subnode.Text = & { ($_.Name + " " + (Get-FriendlySize -Bytes $DirInfo.Sum)) -as [String] }
                        }
      else {
            $subnode.Text = & { ($_.Name + " " + (Get-FriendlySize -Bytes $_.Length)) -as [String] }
            }
        }
      [void]$SelectedNode.Nodes.Add($subnode)
    }

}

#endregion Functions


#region Event Handles

#region MainForm Events

$Form_StateCorrection_Load = {
    
        #Correct the initial state of the form to prevent the .Net maximized form issue
        $MainForm.WindowState = $InitialFormWindowState
    }

$MainForm_Load = {
   $TreeView.SelectedNode = $TreeView.Nodes[0]
    Try {
    #$MainForm.Cursor = 'WaitCursor'
    $TreeView.BeginUpdate()    
         gci $TargetPath -Force | Foreach {
            if ($_ -is [System.IO.FileInfo]) {
                $ImageFiles = switch -Regex ($_.Extension) {
                     "^\.ini|\.dll|\.sys"                         {5}
                     "^\.exe|\.msi"                               {2}
                     "^.jpg|\.png|\.bmp|\.ico|\.jpeg|\.fav|\.svg" {3}
                     "^\.zip|\.rar|\.7z"                          {7}
                     "^\.txt|\.rtf|\.log|\.msg"                   {6}
                     default                                      {0} 
                        }
                    
        $subnode = [System.Windows.Forms.TreeNode]::new()
        $subnode.Name = $_.FullName
        $subnode.Text = & { ($_.Name + " " + (Get-FriendlySize -Bytes $_.Length) -as [string]) }
        $subnode.Tag = @(($_.Attributes).ToString().Split(",").Replace(" ", ""))
        $subnode.ImageIndex = $ImageFiles
        $subnode.SelectedImageIndex = $ImageFiles
                    }
        if ($_ -is [System.IO.DirectoryInfo]) {
          $DirInfo =  $_ | gci -recurse -Force -ErrorAction SilentlyContinue | Measure-Object -Sum length -ErrorAction SilentlyContinue 
          $subnode = [System.Windows.Forms.TreeNode]::new()
          $subnode.Name = $_.FullName
          $subnode.Tag = @(($_.Attributes).ToString().Split(",").Replace(" ", ""))
          $subnode.ImageIndex = 1
          $subnode.SelectedImageIndex = 1
          if ($DirInfo.Count -gt 1) {     
                $subnode.Text = & { ($_.Name + " " + (Get-FriendlySize -Bytes $DirInfo.Sum)) -as [String] }
                            }
          else {
                $subnode.Text = & { ($_.Name + " " + (Get-FriendlySize -Bytes $_.Length)) -as [String] }
                     }
                }
          [void]$TreeView.Nodes[0].Nodes.Add($subnode)
            }

      & $ColorNode
      $TreeView.EndUpdate()
      $TreeView.Refresh()
      $TreeView.SelectedNode.Expand() 
      }
    Catch [Exception]{}
   # Finally {
    #    $mainForm.Cursor = 'Default'
     #       }
 
}

#endregion MainForm Events

#region TreeView & TreeNodes Events

$treeview_BeforeExpand = [System.Windows.Forms.TreeViewCancelEventHandler] {   
    if((-not $_.Node.IsExpanded) -and ($_.Node.Tag -contains "Directory") -and ($_.Node.Clicks -eq 2)) {
        $_.Node.Expand()
            }
    else { $_.Node.Collapse() }
}
 
$TreeView_NodeMouseClick=[System.Windows.Forms.TreeNodeMouseClickEventHandler] {
    $TreeView.SelectedNode = $_.Node
    if ($_.Button -eq 'Right') {  
        $point = [System.Drawing.Point]::new(($RootNode.Bounds.X + 60), $RootNode.Bounds.Y)
        $ContextMenu.Items.Clear()
        [Void]$ContextMenu.Items.Add($PathMenuItem)  
        $ContextMenu.Show($TreeView, $point.X, $point.Y)                         
                } 
    if ((-not $_.Node.IsExpanded) -and (-not $_.Node.Nodes) -and ($_.Node.Tag -contains "Directory") ) {      
        $TreeView.SelectedNode.Nodes.Clear()     
        $TreeView.BeginUpdate()      
        InvokeAddNodes -SelectedNode $TreeView.SelectedNode -IOPath $TreeView.SelectedNode.Name 
        & $ColorNode
        $TreeView.EndUpdate()
        $TreeView.Refresh() 
             }                   
}
            
$TreeView_NodeMouseDoubleClick = [System.Windows.Forms.TreeNodeMouseClickEventHandler] {
    if (($_.Button -eq 'Left') -and (-not $_.Node.IsExpanded) -and ($_.Node.Tag -contains "Directory")) {
    Try {
       $msg = [bool][System.IO.DirectoryInfo]::new($_.Node.Name).GetFileSystemInfos()
       if (!$msg) {
           [System.Windows.Forms.MessageBox]::Show("Directory: $($_.Node.Name) is empty.", " Empty Folder")           
                        }
            }
    Catch [Exception] {
            $errmsg = $PSItem.Exception.Message
           [System.Windows.Forms.MessageBox]::Show($errmsg , " Access Denied")     
                }
        }
}

#endregion TreeView & TreeNodes Events

#region FolderBrowserDialog for Changing Paths

$PathMenuItem_Click = {
    Change-TreePath
}

#endregion FolderBrowserDialog for Changing Paths

#region Closing and Cleaning Form & Controls

$Form_Cleanup_FormClosing = [System.Windows.Forms.FormClosingEventHandler] {

    #Remove all event handlers from the controls and releases garbage collection
    try
    {
        $TreeView.remove_BeforeCheck($TreeView_BeforeCheck)
        $TreeView.remove_AfterCheck($TreeView_AfterCheck)
        $TreeView.remove_BeforeExpand($TreeView_BeforeExpand)
        $TreeView.remove_NodeMouseClick($TreeView_NodeMouseClick)
        $TreeView.remove_DoubleClick($TreeView_DoubleClick)
        $MainForm.remove_Load($MainForm_Load)
        $MainForm.remove_Shown($MainForm_Shown)
        $MainForm.remove_Load($Form_StateCorrection_Load)
        $MainForm.remove_FormClosing($Form_Cleanup_FormClosing)
        $PathMenuItem.remove_Click($PathMenuItem_Click)
        $TreeView.Nodes.Clear()
        $TreeView.Dispose()
        #$thisIO.Dispose(); rv thisIO       
        $MainForm.Dispose()
        rv TreeView
        rv RootNode
        rv TreeView_NodeMouseClick
        rv TreeView_NodeMouseDoubleClick
        rv MainForm 
        rv ContextMenu
        rv iconImage
        rv treeview_BeforeExpand
        rv Form_StateCorrection_Load 
        rv imagelist
        rv PathMenuItem  
        [System.GC]::Collect()
        $Error.Clear()   

 
    }
    catch [Exception]
    { }
}

#endregion Closing and Cleaning Form & Controls

#endregion Event Handles


#Show Disk Tree Form

$null = $MainForm.ShowDialog()

</blockquote>


Что я уже пробовал:

Я пробовал использовать как в моей функции MainForm_Load, так и в функции InvokeAddNodes, используя прямой .net вместо get-childitem, чтобы ускорить его:
<blockquote class="quote"><div class="op">Quote:</div>
$nodecollection =[System.Collections.ArrayList]::new()

  Foreach ($node in ([System.IO.DirectoryInfo]::new($TargetPath).GetFileSystemInfos())) {
    
    if ($node -is [System.IO.FileInfo]) {
    $subnode = [System.Windows.Forms.TreeNode]::new()
    $subnode.Name = $node.FullName
    $subnode.Text = & { ($node.Name + " " + (Get-FriendlySize -Bytes $node.Length) -as [string]) }
    $subnode.Tag = @(($node.Attributes).ToString().Split(",").Replace(" ", ""))
    $nodecollection.Add($subnode)
                }
    if ($node -is [System.IO.DirectoryInfo]) {
      $subnode = [System.Windows.Forms.TreeNode]::new()
      $DirInfo = [System.IO.DirectoryInfo]::new($node.FullName).GetFileSystemInfos() | Measure-Object -Sum length -ErrorAction SilentlyContinue 
      $subnode.Name = $node.FullName
      $subnode.Tag = @(($node.Attributes).ToString().Split(",").Replace(" ", ""))
      if ($DirInfo.Count -gt 1) {     
            $subnode.Text = & { (($node.Name).ToString() + " " + (Get-FriendlySize -Bytes $DirInfo.Sum)) -as [String] }
            $nodecollection.Add($subnode)         
                        }
      else {
            $subnode.Text = & { (($_.Name).ToString() + " " + (Get-FriendlySize -Bytes $_.Length)) -as [String] }
            $nodecollection.Add($subnode)
            }
        }
    }</blockquote>


Однако это дало мне некоторые проблемы с возвратом пустых записей, и он все еще не загружал treeview с первого раза запуска кода. Я был натыкаясь моей голове в течение нескольких недель теперь, и я сдаюсь. Любая помощь будет оценена по достоинству!

0 Ответов