【问题标题】:ListBox Alternating Shading PowerShell列表框交替着色 PowerShell
【发布时间】:2016-12-23 05:46:21
【问题描述】:

我似乎一直在尝试为我的表单添加一些样式。我有一个 ListBox,我想为每隔一行添加备用底纹。这甚至可能吗?我尝试查看 $ListBox.Items 属性,在该属性下方我看不到任何背景选项。有什么想法吗?

$ListBox = New-Object System.Windows.Forms.ListBox
$ListBox.Size = '325,95'
$ListBox.Location = '345,25'
$ListBox.Items.Add("Checking...") > $null

【问题讨论】:

    标签: forms winforms powershell


    【解决方案1】:

    在 Windows 窗体中使用 ListBox 控件执行此操作的唯一方法是劫持每一行的实际绘图。

    首先,更改ListBoxDrawMode属性:

    $ListBox.DrawMode = [System.Windows.Forms.DrawMode]::OwnerDrawFixed
    

    这将允许我们通过the DrawItem event 覆盖项目的图形渲染。

    现在我们只需要定义将绘制项目的函数。我发现this great example in C# 在不影响所选项目的情况下进行交替行颜色。

    幸运的是,C# 是 easily ported to PowerShell:

    $ListBox.add_DrawItem({
    
        param([object]$s, [System.Windows.Forms.DrawItemEventArgs]$e)
    
        if ($e.Index -gt -1)
        {
            Write-Host "Drawing item at index $($e.Index)"
    
            <# If the item is selected set the background color to SystemColors.Highlight 
             or else set the color to either WhiteSmoke or White depending if the item index is even or odd #>
            $color = if(($e.State -band [System.Windows.Forms.DrawItemState]::Selected) -eq [System.Windows.Forms.DrawItemState]::Selected){ 
                [System.Drawing.SystemColors]::Highlight
            }else{
                if($e.Index % 2 -eq 0){
                    [System.Drawing.Color]::WhiteSmoke
                }else{
                    [System.Drawing.Color]::White
                }
            }
    
            # Background item brush
            $backgroundBrush = New-Object System.Drawing.SolidBrush $color
            # Text color brush
            $textBrush = New-Object System.Drawing.SolidBrush $e.ForeColor
    
            # Draw the background
            $e.Graphics.FillRectangle($backgroundBrush, $e.Bounds)
            # Draw the text
            $e.Graphics.DrawString($s.Items[$e.Index], $e.Font, $textBrush, $e.Bounds.Left, $e.Bounds.Top, [System.Drawing.StringFormat]::GenericDefault)
    
            # Clean up
            $backgroundBrush.Dispose()
            $textBrush.Dispose()
        }
        $e.DrawFocusRectangle()
    })
    

    瞧:

    【讨论】:

    • 太棒了!正是我需要的。
    • 乐于助人。但是@boeprox 是对的,考虑使用 WPF 和 XAML 而不是使用 Windows 窗体。更易于维护
    【解决方案2】:

    从您的代码看起来,您没有使用 XAML,但我还是想添加它作为替代方法。

    您可以通过将 XAML 编写为 UI 的前端代码并在触发器中指定设置器属性来设置样式触发器。然后在您的 ListBox 控件中,您可以指定您在 ItemContanerStyle 属性上创建的样式的名称,并将 AlertnationCount 指定为 2,以便它使用您指定的颜色突出显示每一行。

    下面的示例显示了当您将文本添加到列表框时它是如何工作的。

    #Build the GUI
    [xml]$xaml = @"
    <Window 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        x:Name="Window" Title="Initial Window" WindowStartupLocation = "CenterScreen" 
        Width = "313" Height = "800" ShowInTaskbar = "True" Background = "lightgray"> 
        <ScrollViewer VerticalScrollBarVisibility="Auto">
            <StackPanel >
                <StackPanel.Resources>
                    <Style x:Key="AlternatingRowStyle" TargetType="{x:Type Control}" >
                        <Setter Property="Background" Value="LightBlue"/>
                        <Setter Property="Foreground" Value="Black"/>
                        <Style.Triggers>
                            <Trigger Property="ItemsControl.AlternationIndex" Value="1">                            
                                <Setter Property="Background" Value="White"/>
                                <Setter Property="Foreground" Value="Black"/>                                
                            </Trigger>                            
                        </Style.Triggers>
                    </Style>     
                </StackPanel.Resources>
                <TextBox  IsReadOnly="True" TextWrapping="Wrap">
                    Type something and click Add
                </TextBox>
                <TextBox x:Name = "inputbox"/>
                <Button x:Name="button1" Content="Add"/>
                <Button x:Name="button2" Content="Remove"/>
                <Expander IsExpanded="True">
                    <ListBox x:Name="listbox" SelectionMode="Extended" AlternationCount="2"                 
                    ItemContainerStyle="{StaticResource AlternatingRowStyle}"/>
                </Expander >
            </StackPanel>
        </ScrollViewer >
    </Window>
    "@
    
    $reader=(New-Object System.Xml.XmlNodeReader $xaml)
    $Window=[Windows.Markup.XamlReader]::Load( $reader )
     
    #region Connect to Controls    
    Write-Verbose "Connecting to controls"
    $xaml.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]") | ForEach {
        New-Variable -Name $_.Name -Value $Window.FindName($_.Name) -Force
    }
    #endregion Connect to Controls
    
    $Window.Add_SourceInitialized({
        #Have to have something initially in the collection
        $Script:observableCollection = New-Object System.Collections.ObjectModel.ObservableCollection[string]
        $listbox.ItemsSource = $observableCollection
        $inputbox.Focus()
    })
     
    #Events
    $button1.Add_Click({
         $observableCollection.Add($inputbox.text)
         $inputbox.Clear()
    })
    $button2.Add_Click({
        ForEach ($item in @($listbox.SelectedItems)) {
            $observableCollection.Remove($item)
        }
    }) 
    $Window.ShowDialog() | Out-Null
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-10-25
      • 2011-06-15
      • 1970-01-01
      • 2011-01-19
      • 2010-09-06
      • 1970-01-01
      • 2020-12-30
      相关资源
      最近更新 更多