首页 > 其他分享 >WPF仿VS TreeView

WPF仿VS TreeView

时间:2023-11-07 17:24:30浏览次数:32  
标签:string get FileType VS Path new WPF TreeView public

    [TemplatePart(Name = "PART_Content", Type = typeof(ToggleButton))]
    [TemplatePart(Name = "Expander", Type = typeof(Panel))]
    public class OTreeViewItem : TreeViewItem
    {
        Panel? partContent;
        ToggleButton? partExpander;



        public Visibility ExpanderVisible
        {
            get { return (Visibility)GetValue(ExpanderVisibleProperty); }
            set { SetValue(ExpanderVisibleProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ExpanderVisible.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ExpanderVisibleProperty =
            DependencyProperty.Register("ExpanderVisible", typeof(Visibility), typeof(OTreeViewItem), new PropertyMetadata(Visibility.Hidden));


        static OTreeViewItem()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(OTreeViewItem), new FrameworkPropertyMetadata(typeof(OTreeViewItem)));
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            partExpander = (ToggleButton)GetTemplateChild("Expander");//Expander
            partContent = (Panel)GetTemplateChild("PART_Content");
        }

        protected override Size MeasureOverride(Size constraint)
        {
            var a = this.Parent;
            int i = 0;
            while (a is TreeViewItem item)
            {
                i++;
                a = item.Parent;
            }
            partContent!.Margin = new Thickness(i * 10.0, 0, 0, 0);
            return base.MeasureOverride(constraint);
        }
    }
View Code
    <SolidColorBrush x:Key="TreeViewItem.TreeArrow.Static.Stroke" Color="#FF818181"/>
    <SolidColorBrush x:Key="TreeViewItem.TreeArrow.Static.Fill" Color="#FFFFFFFF"/>
    <SolidColorBrush x:Key="TreeViewItem.TreeArrow.MouseOver.Stroke" Color="#FF27C7F7"/>
    <SolidColorBrush x:Key="TreeViewItem.TreeArrow.MouseOver.Fill" Color="#FFCCEEFB"/>
    <SolidColorBrush x:Key="TreeViewItem.TreeArrow.Static.Checked.Stroke" Color="#FF262626"/>
    <SolidColorBrush x:Key="TreeViewItem.TreeArrow.Static.Checked.Fill" Color="#FF595959"/>
    <SolidColorBrush x:Key="TreeViewItem.TreeArrow.MouseOver.Checked.Stroke" Color="#FF1CC4F7"/>
    <SolidColorBrush x:Key="TreeViewItem.TreeArrow.MouseOver.Checked.Fill" Color="#FF82DFFB"/>
    <PathGeometry x:Key="TreeArrow" Figures="M0,0 L0,6 L6,0 z"/>
    <Style x:Key="ExpandCollapseToggleStyle" TargetType="{x:Type ToggleButton}">
        <Setter Property="Focusable" Value="False"/>
        <Setter Property="Width" Value="16"/>
        <Setter Property="Height" Value="16"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ToggleButton}">
                    <Border Background="Transparent" Height="16" Padding="5,5,5,5" Width="16">
                        <Path x:Name="ExpandPath" Data="{StaticResource TreeArrow}" Fill="{StaticResource TreeViewItem.TreeArrow.Static.Fill}" Stroke="{StaticResource TreeViewItem.TreeArrow.Static.Stroke}">
                            <Path.RenderTransform>
                                <RotateTransform Angle="135" CenterY="3" CenterX="3"/>
                            </Path.RenderTransform>
                        </Path>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsChecked" Value="True">
                            <Setter Property="RenderTransform" TargetName="ExpandPath">
                                <Setter.Value>
                                    <RotateTransform Angle="180" CenterY="3" CenterX="3"/>
                                </Setter.Value>
                            </Setter>
                            <Setter Property="Fill" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.Static.Checked.Fill}"/>
                            <Setter Property="Stroke" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.Static.Checked.Stroke}"/>
                        </Trigger>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter Property="Stroke" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.MouseOver.Stroke}"/>
                            <Setter Property="Fill" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.MouseOver.Fill}"/>
                        </Trigger>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="IsMouseOver" Value="True"/>
                                <Condition Property="IsChecked" Value="True"/>
                            </MultiTrigger.Conditions>
                            <Setter Property="Stroke" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.MouseOver.Checked.Stroke}"/>
                            <Setter Property="Fill" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.MouseOver.Checked.Fill}"/>
                        </MultiTrigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style x:Key="TreeViewItemFocusVisual">
        <Setter Property="Control.Template">
            <Setter.Value>
                <ControlTemplate>
                    <Rectangle/>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style TargetType="{x:Type control:OTreeViewItem}">
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
        <Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
        <Setter Property="Padding" Value="1,0,0,0"/>
        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
        <Setter Property="FocusVisualStyle" Value="{StaticResource TreeViewItemFocusVisual}"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type control:OTreeViewItem}">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition/>
                        </Grid.RowDefinitions>
                        <Border x:Name="Bd" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
                            <DockPanel x:Name="PART_Content">
                                <ToggleButton x:Name="Expander" ClickMode="Press" Visibility="{TemplateBinding ExpanderVisible}" IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource ExpandCollapseToggleStyle}"/>
                                <ContentPresenter x:Name="PART_Header" ContentSource="Header" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                            </DockPanel>
                        </Border>
                        <ItemsPresenter x:Name="ItemsHost" Grid.Row="1"/>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsExpanded" Value="false">
                            <Setter Property="Visibility" TargetName="ItemsHost" Value="Collapsed"/>
                        </Trigger>
                        <Trigger Property="IsSelected" Value="true">
                            <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
                        </Trigger>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="IsSelected" Value="true"/>
                                <Condition Property="IsSelectionActive" Value="false"/>
                            </MultiTrigger.Conditions>
                            <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/>
                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}}"/>
                        </MultiTrigger>
                        <Trigger Property="IsEnabled" Value="false">
                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Style.Triggers>
            <Trigger Property="VirtualizingPanel.IsVirtualizing" Value="true">
                <Setter Property="ItemsPanel">
                    <Setter.Value>
                        <ItemsPanelTemplate>
                            <VirtualizingStackPanel/>
                        </ItemsPanelTemplate>
                    </Setter.Value>
                </Setter>
            </Trigger>
        </Style.Triggers>
    </Style>
View Code
[StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(OTreeViewItem))]
public class OTreeView : TreeView
{
    protected override DependencyObject GetContainerForItemOverride()
    {
        return new OTreeViewItem();
    }
}
View Code

使用参考(文件夹目录):

    public class TextboxDialog : Window
    {
        public TextBox TextBox { get; set; }
        public EventHandler<string> Resulted { get; set; }
        public TextboxDialog(Window owner)
        {
            Owner = owner;
            SizeToContent = SizeToContent.WidthAndHeight;
            WindowStyle = WindowStyle.None;
            WindowStartupLocation = WindowStartupLocation.CenterOwner;
            Loaded += TextboxDialog_Loaded;
        }

        private void TextboxDialog_Loaded(object sender, RoutedEventArgs e)
        {
            KeyUp += (s, e) =>
            {
                if (e.Key == Key.Escape) Cancel();
            };
            if (TextBox == null)
            {
                TextBox = new TextBox
                {
                    MinWidth = 300,
                    Height = 25,
                    VerticalContentAlignment = VerticalAlignment.Center,
                };
            }
            TextBox.Focus();
            TextBox.KeyDown += (s, e) =>
            {
                if (e.Key == Key.Enter)
                {
                    string text = TextBox.Text.Trim();
                    Resulted?.Invoke(this, text);
                    DialogResult = true;
                    Close();
                }
            };
            Content = TextBox;
        }

        void Cancel()
        {
            DialogResult = false;
            Close();
        }
    }

    public class FileNode
    {
        public FileNode Parent { get; set; }
        public virtual FileType FileType { get; set; }
        public string Value { get; set; }
        public string Path { get; set; }
        public SimpleCommand DeleteCmd { get; set; }
        public SimpleCommand RenameCmd { get; set; }

        public FileNode()
        {
            DeleteCmd = new SimpleCommand(Delete);
            RenameCmd = new SimpleCommand(Rename);
        }

        protected virtual void Rename()
        {
            var window = new TextboxDialog(App.Current.MainWindow);
            window.Resulted += (s, text) =>
            {
                if (string.IsNullOrWhiteSpace(text)) return;
                string path = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(Path), text);
                if (Directory.Exists(path))
                {
                    MessageBox.Show("名称已存在");
                    return;
                }
                File.Move(Path, path);
                WpfApp2.Commons.BindingBase.Instance.RaisePropertyChanged(this, nameof(Value));
            };
            window.ShowDialog();
        }

        void Delete()
        {
            if(FileType== FileType.Folder)
                IOHelper.DeleteDirectory(Path);
            else
                IOHelper.DeleteFile(Path);
            (Parent as FolderNode)?.Children.Remove(this);
        }

        public override string ToString()
        {
            return Path;
        }
    }

    public class FolderNode : FileNode
    {
        [DllImport("shlwapi.dll")]
        public static extern bool PathIsDirectoryEmpty(string pszPath);

        public override FileType FileType { get => FileType.Folder; }
        public bool IsEmpty { get; set; }
        public ObservableCollection<FileNode> Children { get; set; } = new ObservableCollection<FileNode>();

        public SimpleCommand NewDirectoryCmd { get; set; }
        public SimpleCommand LoadChildrenCmd { get; set; }


        public FolderNode()
        {
            NewDirectoryCmd = new SimpleCommand(NewDirectory);
            LoadChildrenCmd = new SimpleCommand(LoadChildren);
        }

        protected override void Rename()
        {
            var window = new TextboxDialog(App.Current.MainWindow);
            window.Resulted += (s, text) =>
            {
                if (string.IsNullOrWhiteSpace(text)) return;
                string path = System.IO.Path.Combine(new DirectoryInfo(Path).Parent.FullName, text);
                if (Directory.Exists(path))
                {
                    MessageBox.Show("名称已存在");
                    return;
                }
                Directory.Move(Path, path);
                (Parent as FolderNode).LoadChildren();
            };
            window.ShowDialog();
        }

        private void NewDirectory()
        {
            var window = new TextboxDialog(App.Current.MainWindow);
            window.Resulted += (s, text) =>
            {
                if (string.IsNullOrWhiteSpace(text)) return;
                string path = System.IO.Path.Combine(Path, text);
                if (Directory.Exists(path))
                {
                    MessageBox.Show("名称已存在");
                    return;
                }
                Directory.CreateDirectory(path);
                AddChild(path, text, FileType.Folder);
            };
            window.ShowDialog();
        }

        public FileNode AddChild(string path, string value, FileType fileType)
        {
            var child = new FileNode();
            if(fileType == FileType.Folder)
            {
                var c = new FolderNode();
                c.IsEmpty = PathIsDirectoryEmpty(path);
                child = c;
            }
            child.Path = path;
            child.Value = value;
            child.Parent = this;
            Children.Add(child);
            return child;
        }

        public void LoadChildren()
        {
            try
            {
                Children?.Clear();
                string[] dirs = System.IO.Directory.GetDirectories(Path);
                foreach (var dir in dirs)
                {
                    DirectoryInfo info = new DirectoryInfo(dir);
                    if ((info.Attributes & FileAttributes.System) != 0) continue;
                    _ = AddChild(dir, dir.Split("\\").Last(), FileType.Folder);
                }
                string[] files = System.IO.Directory.GetFiles(Path);
                foreach (var file in files)
                {
                    FileInfo info = new FileInfo(file);
                    if ((info.Attributes & FileAttributes.System) != 0) continue;
                    _ = AddChild(file, file.Split("\\").Last(), FileType.File);
                }
            }
            catch { }
        }
    }
    public enum FileType { File, Folder }
View Code

XAML:

<Window.Resources>
    <ContextMenu x:Key="FolderContextMenu">
        <MenuItem Header="新建文件夹" Command="{Binding NewDirectoryCmd}"/>
        <MenuItem Header="重命名" Command="{Binding RenameCmd}"/>
        <MenuItem Header="删除" Command="{Binding DeleteCmd}"/>
    </ContextMenu>
    <ContextMenu x:Key="FileContextMenu">
        <MenuItem Header="重命名" Command="{Binding RenameCmd}"/>
        <MenuItem Header="删除" Command="{Binding DeleteCmd}"/>
    </ContextMenu>
</Window.Resources>
<control:OTreeView x:Name="tvRoot">
    <control:OTreeView.ItemContainerStyle>
        <Style TargetType="control:OTreeViewItem" BasedOn="{StaticResource OTreeViewItemStyle}">
            <Setter Property="ExpandCommand" Value="{Binding LoadChildrenCmd}"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding FileType}" Value="Folder">
                    <Setter Property="ContextMenu" Value="{StaticResource FolderContextMenu}"/>
                </DataTrigger>
                <DataTrigger Binding="{Binding FileType}" Value="File">
                    <Setter Property="ContextMenu" Value="{StaticResource FileContextMenu}"/>
                </DataTrigger>
                <DataTrigger Binding="{Binding IsEmpty}" Value="True">
                    <Setter Property="ExpanderVisible" Value="Hidden"/>
                </DataTrigger>
                <DataTrigger Binding="{Binding IsEmpty}" Value="False">
                    <Setter Property="ExpanderVisible" Value="Visible"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </control:OTreeView.ItemContainerStyle>
    <control:OTreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding Children}">
            <TextBlock Text="{Binding Value}" Margin="4,2,0,2"/>
        </HierarchicalDataTemplate>
    </control:OTreeView.ItemTemplate>
</control:OTreeView>

C#:

FolderNode project = new FolderNode { Path = "D:\\", FileType = FileType.Folder };
project.LoadChildrenCmd.Execute(null);
tvRoot.ItemsSource = project.Children;

 

标签:string,get,FileType,VS,Path,new,WPF,TreeView,public
From: https://www.cnblogs.com/RedSky/p/17805962.html

相关文章

  • WPF开发的小巧、美观桌面快捷工具GeekDesk开源项目--极客桌面
    今天给大家推荐一个基于WPF开发的,专门为程序员定制的桌面快捷工具。项目简介这是基于.Net+WPF开发的,一个小巧、UI美观的快捷工具。此项目发布以来就受到大家的喜欢,代码结构清晰非常适合用来学习。项目还在持续迭代中,有部分小问题,用来学习、体验完全没问题。作者一直在迭代升级......
  • [JSON] Fastjson 之版本对比:Fastjson vs Fastjson2
    1Fastjson21.1简述FASTJSON相对其他JSON库的特点是快,从2011年fastjson发布1.1.x版本之后,其性能从未被其他Java实现的JSON库超越。Fastjson2相对Fastjson1版本可以说是一次完全重构。这里从代码的角度,分析两者的一些区别;并总结一些新的,让小伙伴们使用Fastjson2或者进......
  • vs2015编译glib2.5.0
    1、首先安装vs2015,以及下载一个glib2.50的源码包2、编译glib的问题①首先解决提示找不到libintl.h的问题需要编译安装libintl模块,可通过下载到glib仓库下载gettext-runtime-dev_0.18.1.1-1_win32包,里面提供了libintl.h和intl.lib②解决找不到pcre.h的问题到官网下载pcre安装......
  • 文心一言 VS 讯飞星火 VS chatgpt (130)-- 算法导论11.2 2题
    二、用go语言,对于一个用链接法解决冲突的散列表,说明将关键字5,28,19,15,20,33,12,17,10插入到该表中的过程。设该表中有9个槽位,并设其散列函数为h(k)=kmod9。文心一言:在这个问题中,我们使用Go语言来解决一个散列(Hash)表的问题,该问题需要我们使用链接法解决冲突。我们的散......
  • VSS使用手册(VSS 6.0d/Visual SourceSafe)
    1VSS概述    版本控制是工作组软件开发中的重要方面,它能防止意外的文件丢失、允许反追踪到早期版本、并能对版本进行分支、合并和管理。在软件开发和您需要比较两种版本的文件或找回早期版本的文件时,源代码的控制是非常有用的。VisualSourceSafe是一种源代码控制系统,它......
  • vscode快捷输入vue2,vue3,模板
    { //Placeyoursnippetsforvuehere.Eachsnippetisdefinedunderasnippetnameandhasaprefix,bodyand //description.Theprefixiswhatisusedtotriggerthesnippetandthebodywillbeexpandedandinserted.Possiblevariablesare: //$1,......
  • 界面控件DevExpress WPF PDF Viewer,更快实现应用的PDF文档浏览
    DevExpressWPFPDFViewer控件可以轻松地直接在Windows应用程序中显示PDF文档,而无需在最终用户的机器上安装外部PDF查看器。P.S:DevExpressWPF拥有120+个控件和库,将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpressWPF能创建有着强大互动功能的XAML基础应......
  • 文心一言 VS 讯飞星火 VS chatgpt (129)-- 算法导论11.1 4题
    四、用go语言,我们希望在一个非常大的数组上,通过利用直接寻址的方式来实现一个字典。开始时该数组中可能包含一些无用信息,但要对整个数组进行初始化是不太实际的,因为该数组的规模太大。请给出在大数组上实现直接寻址字典的方案。每个存储对象占用O(1)空间;SEARCH、INSERT和DELETE操......
  • wpf 记一次诡异的PreviewMouseLeftButtonDown 无法触发问题
    1、原始代码<Grid><i:Interaction.Triggers><i:EventTriggerEventName="PreviewMouseLeftButtonDown">......
  • 文心一言 VS 讯飞星火 VS chatgpt (129)-- 算法导论11.1 4题
    四、用go语言,我们希望在一个非常大的数组上,通过利用直接寻址的方式来实现一个字典。开始时该数组中可能包含一些无用信息,但要对整个数组进行初始化是不太实际的,因为该数组的规模太大。请给出在大数组上实现直接寻址字典的方案。每个存储对象占用O(1)空间;SEARCH、INSERT和DELETE操......