带有动态图像的PowerShell WPF TreeView

问题描述 投票:0回答:1

我正在开发一个项目,其中有一个 PowerShell 驱动的 UI,其中有一个包含一个选项的树视图列表。我按照这个博客PowerShell WPF - 自定义 TreeView 图标...很棒的文章顺便说一句,该代码运行得很好!我想根据其项目标签为不同文件自定义具有不同图像的树列表。我可以使用 png 图像源和 DataTriggers 让它工作,但是我试图将所有图像作为 SVG 嵌入到画布模板中。我知道如何让它工作的唯一方法是使用 VisualBrush 元素,但我似乎无法让它在 Treeview.resource 框架元素中工作。这是我到目前为止所拥有的:

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="TreeView"
        Height="600" Width="800"
        ResizeMode="NoResize"
        WindowStartupLocation="CenterScreen"
        ShowInTaskbar="False" Topmost="True">  
    <Window.Resources>
        
        <ResourceDictionary>

            <ResourceDictionary.MergedDictionaries>
                    <ResourceDictionary Source="Resources\Icons.xaml" />
                    <ResourceDictionary Source="Resources\TabControl_LeftSideStyle.xaml" />
                    <ResourceDictionary Source="Resources\TreeViewItem_StandardStyle.xaml" />

                </ResourceDictionary.MergedDictionaries>
            
            
            <Style TargetType="{x:Type Window}">
                <Setter Property="FontFamily" Value="Segoe UI" />
                <Setter Property="FontWeight" Value="Light" />
                <Setter Property="BorderBrush" Value="#004275" />
                <Setter Property="BorderThickness" Value="0.5" />
            </Style>

            <HierarchicalDataTemplate x:Key="CheckBoxItemTemplate" ItemsSource="{Binding Children, Mode=OneTime}">
                <StackPanel Orientation="Horizontal">
                    <CheckBox Focusable="False" IsChecked="{Binding IsChecked}" VerticalAlignment="Center" />
                    <ContentPresenter Content="{Binding Name, Mode=OneTime}" Margin="2,0" />
                </StackPanel>
            </HierarchicalDataTemplate>
            </ResourceDictionary>
        </Window.Resources>
    
    <Grid>
        
        <Rectangle Fill="#004275" HorizontalAlignment="Left" Height="600" VerticalAlignment="Center" Width="150"/>
        <Rectangle Fill="#FFF4F4F5" HorizontalAlignment="Right" Height="600" VerticalAlignment="Center" Width="156"/>
        <StackPanel HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10">
            <Image x:Name="_wizMainLogo" Height="48" Width="132" Stretch="Uniform" />
        </StackPanel>

        <!-- START TAB MENU -->
        <TabControl x:Name="_wizTabControl" Style="{DynamicResource TabControlLeftSide}" Width="800" Height="550" HorizontalAlignment="Center" VerticalAlignment="Top">
            <TabItem x:Name="_wizid" Header="Tree view" Style="{DynamicResource TabItemsWhite}" Width="150" Margin="0" IsEnabled="False">
                <Grid x:Name="TabLayout" Margin="0" Grid.ColumnSpan="2" FocusManager.FocusedElement="{Binding ElementName=tsTree}">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="490"></ColumnDefinition>
                        <ColumnDefinition Width="150"></ColumnDefinition>
                    </Grid.ColumnDefinitions>
                    <Label x:Name="TabMainTitle" Grid.Column="0" HorizontalAlignment="Left" Margin="10,20,0,0" VerticalAlignment="Top" FontSize="22" Content="Tree view list with icons"/>
                    <Rectangle Grid.Column="0" Fill="HotPink" HorizontalAlignment="Right" Height="40" Width="40" Margin="0,20,13.5,0" VerticalAlignment="Top">
                        <Rectangle.OpacityMask>
                            <VisualBrush Stretch="Fill" Visual="{DynamicResource icons_listoutline}"/>
                        </Rectangle.OpacityMask>
                    </Rectangle>


                    <Label x:Name="TabSubTitle" FontSize="14" HorizontalAlignment="Left" Margin="10,73,0,0" VerticalAlignment="Top" Content="Search for item in list"/>
                    <TextBox x:Name="TabSearch" HorizontalAlignment="Left" Height="31" Margin="10,103,0,0" TextWrapping="Wrap" Text="Search..." VerticalAlignment="Top" Width="331" Foreground='Gray' VerticalContentAlignment="Center" FontSize="18"/>
                    <Button x:Name="TabSearchClear" Content="Clear" Height="31" Width="63" HorizontalAlignment="Left" VerticalAlignment="Bottom" FontSize="10" Padding="2" Margin="414,0,0,416" />
                    <Button x:Name="TabSearchEnter" Content="Search" Height="31" Width="63" HorizontalAlignment="Left" VerticalAlignment="Bottom" FontSize="10" Padding="2" Margin="346,0,0,416" />

                    <Button x:Name="TabExpand" Content="Expand All" Height="25" Width="113" HorizontalAlignment="Left" VerticalAlignment="Bottom" FontSize="10" Padding="2" Margin="10,0,0,386" />
                    <Button x:Name="TabCollapse" Content="Collapse All" Height="25" Width="113" HorizontalAlignment="Left" VerticalAlignment="Bottom" FontSize="10" Padding="2" Margin="128,0,0,386" />

                    <TreeView x:Name="TabTree" HorizontalAlignment="Left" Height="371" Margin="10,169,0,0" VerticalAlignment="Top" Width="467" FontSize="14"  
                                ItemContainerStyle="{StaticResource TreeViewItemStandard}" 
                                ItemTemplate="{StaticResource CheckBoxItemTemplate}" >
                        <TreeView.Resources>
                            <Style TargetType="{x:Type TreeViewItem}">
                                <Setter Property="HeaderTemplate">
                                    <Setter.Value>
                            
                                        <DataTemplate>
                                            <StackPanel Orientation="Horizontal">
                                              <Image Name="TreeNodeIMG" Width="20" Height="20" Stretch="Fill">
                                                <Image.Style>
                                                  <Style TargetType="{x:Type Image}">
                                                    <Style.Triggers>
                                                        <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=TreeViewItem}, Path=Tag[0]}" Value="folder">
                                                            <Setter Property="Source" Value="images\folder.png"/>
                                                        </DataTrigger>
                                                        <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=TreeViewItem}, Path=Tag[0]}" Value="file">
                                                            <Setter Property="Source" Value="images\file.png"/>
                                                        </DataTrigger>
      
                                                    </Style.Triggers>
                                                  </Style>
                                                </Image.Style>
                                              </Image>
                                              <TextBlock VerticalAlignment="Center" Text="{Binding}" Margin="5,0" />
                                            </StackPanel>
                                          </DataTemplate>

                                    </Setter.Value>
                                </Setter>
                            </Style>
                        </TreeView.Resources> 

                    </TreeView>

                    <Label Content="More Info" Grid.Column="1" FontSize="14" HorizontalAlignment="Left" Margin="10,31,0,0" VerticalAlignment="Top" Foreground="LightSlateGray" />
                    <TextBlock x:Name="TabMoreInfo" Grid.Column="1" HorizontalAlignment="Left" Margin="10,89,0,0" Width="136" TextWrapping="Wrap" VerticalAlignment="Top" Height="422">
                        <Run Text="orem ipsum dolor sit amet, consectetur adipiscing elit. Morbi risus mi, consequat in ultricies eu, euismod nec eros. Pellentesque vel augue sed enim euismod sodales varius a ipsum. "/>
                    </TextBlock>
                </Grid>
            </TabItem>
        </TabControl>
        
    </Grid>
    
</Window>

我正在测试的 PowerShell 脚本示例是这样的:

#$ErrorActionPreference='Stop'
##*=============================================
##* VARIABLES
##*=============================================
[string]$ResourceRoot = ($PWD.ProviderPath, $PSScriptRoot)[[bool]$PSScriptRoot]


##*=============================================
##* LOAD UI
##*=============================================
[System.Reflection.Assembly]::LoadWithPartialName('presentationframework') | out-null

function LoadXaml ($filename){
    $XamlLoader=(New-Object System.Xml.XmlDocument)
    $XamlLoader.Load($filename)
    return $XamlLoader
}
$XamlMainWindow=LoadXaml($ResourceRoot+"\MainWindow.xaml")
$reader = (New-Object System.Xml.XmlNodeReader $XamlMainWindow)
$Form = [Windows.Markup.XamlReader]::Load($reader)


$Global:FolderTree = $Form.FindName("TabTree")

##*=============================================
##* MAIN
##*=============================================

$dummyNode = $null
$preselect = 'rootFile1.txt'


$AllFiles  = [IO.Directory]::GetFiles("$ResourceRoot\Test")
$AllDirectory = [IO.Directory]::GetDirectories("$ResourceRoot\Test")

# ================== Handle Folders ===========================
#$folder = $AllDirectory[0]
foreach ($folder in $AllDirectory){

    $treeViewItem = [Windows.Controls.TreeViewItem]::new()
    $treeViewItem.Header = $folder.Substring($folder.LastIndexOf("\") + 1)
    $treeViewItem.Tag = @("folder",$folder)
    $treeViewItem.Items.Add($dummyNode) | Out-Null

    
    $treeViewItem.Add_Expanded({
        Write-Host $_.OriginalSource.Header  " is expanded"
        TreeExpanded($_.OriginalSource)
    })
    $FolderTree.Items.Add($treeViewItem)| Out-Null

}

# ================== Handle Files ===========================
foreach ($file in $AllFiles){

    $treeViewItem = [Windows.Controls.TreeViewItem]::new()
    $treeViewItem.Header = $file.Substring($file.LastIndexOf("\") + 1)
    $treeViewItem.Tag = @("file",$file) 
    $FolderTree.Items.Add($treeViewItem)| Out-Null
    If($treeViewItem.Header -eq $preselect){
        $treeViewItem.IsSelected = $true
        Write-Host ("pre selected Item: {0}" -f $treeViewItem.Header)
    }Else{
        Write-Host ("Added Item: {0}" -f $treeViewItem.Header)
    }

    $treeViewItem.Add_PreviewMouseLeftButtonDown({
        [System.Windows.Controls.TreeViewItem]$sender = $args[0]
        [System.Windows.RoutedEventArgs]$e = $args[1]
        Write-Host "Left Click: $($sender.Tag)"
    })

    $treeViewItem.Add_PreviewMouseRightButtonDown({
        [System.Windows.Controls.TreeViewItem]$sender = $args[0]
        [System.Windows.RoutedEventArgs]$e = $args[1]
        Write-Host "Right Click: $($sender.Tag)"
    })

}


Function TreeExpanded($sender){
    
    $global:item = [Windows.Controls.TreeViewItem]$sender
    
    If ($item.Items.Count -eq 1 -and $item.Items[0] -eq $dummyNode)
    {
        $item.Items.Clear();
        Try
        {
            
            foreach ($string in [IO.Directory]::GetDirectories($item.Tag[1].ToString()))
            {
                $subitem = [Windows.Controls.TreeViewItem]::new();
                $subitem.Header = $string.Substring($string.LastIndexOf("\") + 1)
                $subitem.Tag = @("folder",$string)
                $subitem.Items.Add($dummyNode)
                
                $subitem.Add_Expanded({
                    TreeExpanded($_.OriginalSource)
                })
                $item.Items.Add($subitem) | Out-Null
            }

            foreach ($file in [IO.Directory]::GetFiles($item.Tag[1].ToString())){

                $subitem = [Windows.Controls.TreeViewItem]::new()
                $subitem.Header = $file.Substring($file.LastIndexOf("\") + 1)
                $subitem.Tag = @("file",$file) 
                $item.Items.Add($subitem)| Out-Null

                If($subitem.Header -eq $preselect){
                    $subitem.IsSelected = $true
                    Write-Host ("pre-selected Item: {0}" -f $subitem.Header)
                }Else{
                    Write-Host ("Added Item: {0}" -f $subitem.Header)
                }


                $subitem.Add_PreviewMouseLeftButtonDown({
                    [System.Windows.Controls.TreeViewItem]$sender = $args[0]
                    [System.Windows.RoutedEventArgs]$e = $args[1]
                    Write-Host "Left Click: $($sender.Tag)"
                })
            }
        }   
        Catch [Exception] { }
    }
     
}

##*=============================================
##* SHOW UI
##*=============================================

$Form.ShowDialog() | Out-Null

当我运行代码时,它看起来像这样:

这是根级别文件夹中图像未显示的问题,但没什么大不了的,除非有人也有答案......

画布资源字典文件中有这个:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Canvas x:Key="icon_file" Width="24" Height="24">
        <Path Stretch="Fill" Fill="White" Data="M3 5V19H20V5H3M7 7V9H5V7H7M5 13V11H7V13H5M5 15H7V17H5V15M18 17H9V15H18V17M18 13H9V11H18V13M18 9H9V7H18V9Z" />
    </Canvas>

    <Canvas x:Key="icon_folder" Width="24" Height="24">
        <Path Width="20" Height="20" Fill="White" Stretch="Uniform" Data="M19,20H4C2.89,20 2,19.1 2,18V6C2,4.89 2.89,4 4,4H10L12,6H19A2,2 0 0,1 21,8H21L4,8V18L6.14,10H23.21L20.93,18.5C20.7,19.37 19.92,20 19,20Z"/>
    </Canvas>

</ResourceDictionary>

我让它工作的唯一方法是在 xaml 中使用此代码

<TreeView.Resources>
    <Style TargetType="{x:Type TreeViewItem}">
        <Setter Property="HeaderTemplate">
            <Setter.Value>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">

                        <Rectangle Fill="Green" HorizontalAlignment="Right" Height="20" Width="20" VerticalAlignment="Top">
                            <Rectangle.OpacityMask>
                                <VisualBrush Stretch="Fill" Visual="{DynamicResource icons_folder}"/>
                            </Rectangle.OpacityMask>
                        </Rectangle>

                        <TextBlock Text="{Binding}" Margin="5,0" />
                    </StackPanel>
                </DataTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</TreeView.Resources>

尽管这会将整个图像填充为填充颜色,但它确实会显示,但对于文件夹和文件来说都是相同的。现在,如果我尝试使用画布图像和数据触发器的绑定,则会收到数据类型错误。我在网上没有找到任何关于如何将 svg 数据绑定与树视图和数据触发器结合使用的内容。那里有 C# 编码的分配,但正在寻找 PowerShell 和 .Net 解决方案。

尽管我认为在 XAML 代码中完成此操作会更容易,但我确实尝试在 PowerShell 中以编程方式更改图像......但这也惨败。 有什么想法吗?

我需要你的一些专业技能!谢谢!!!

wpf powershell xaml svg datatrigger
1个回答
0
投票

您可以将

Image
中的
HeaderTemplate
替换为显示您的
ContentControl
资源之一的
Canvas

<Style TargetType="{x:Type TreeViewItem}">
    <Setter Property="HeaderTemplate">
        <Setter.Value>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <ContentControl>
                        <ContentControl.Style>
                            <Style TargetType="ContentControl">
                                <Style.Triggers>
                                    <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=TreeViewItem}, Path=Tag[0]}" Value="folder">
                                        <Setter Property="Content" Value="{DynamicResource icon_folder}" />
                                    </DataTrigger>
                                    <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=TreeViewItem}, Path=Tag[0]}" Value="file">
                                        <Setter Property="Content" Value="{DynamicResource icon_file}" />
                                    </DataTrigger>
                                </Style.Triggers>
                            </Style>
                        </ContentControl.Style>
                    </ContentControl>
                    <TextBlock VerticalAlignment="Center" Text="{Binding}" Margin="5,0" />
                </StackPanel>
            </DataTemplate>
        </Setter.Value>
    </Setter>
</Style>
© www.soinside.com 2019 - 2024. All rights reserved.