WPF 保姆級教程怎麼實現一個樹形菜單

来源:https://www.cnblogs.com/lvpp13/p/18400310
-Advertisement-
Play Games

先看一下效果吧: 我們直接通過改造一下原版的TreeView來實現上面這個效果 我們先創建一個普通的TreeView 代碼很簡單: <TreeView> <TreeViewItem Header="人事部"/> <TreeViewItem Header="技術部"> <TreeViewItem He ...


先看一下效果吧:

    

我們直接通過改造一下原版的TreeView來實現上面這個效果

我們先創建一個普通的TreeView

代碼很簡單:

        <TreeView>
            <TreeViewItem Header="人事部"/>
            <TreeViewItem Header="技術部">
                <TreeViewItem Header="技術部-1"/>
                <TreeViewItem Header="技術部-1"/>
            </TreeViewItem>
            <TreeViewItem Header="財務部"/>
        </TreeView>

實現的效果如下:

如果把這個當成是項目的菜單欄,應該會被領導罵死,一個是不夠靈活,數據是寫死的;二是樣式不好看,只有點文字部分才會展開。

創建一下模板

直接在設計器中右鍵我們的item,編輯副本,點擊確定,我們會得到下麵一段代碼

裡面有一個叫Bd的border,我們把這個border的背景色去掉,然後我們自己去創建兩個新的border

<Border Background="Transparent" Margin="-200,0,-200,0" Grid.ColumnSpan="4"/>
<Border x:Name="bd1" Background="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" 
        Margin="-200,0,-200,0" Visibility="Hidden" Grid.ColumnSpan="4">
    <Border.Effect>
        <DropShadowEffect BlurRadius="5" ShadowDepth="2"/>
    </Border.Effect>
</Border>
<ToggleButton x:Name="Expander" ClickMode="Press" 
              IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource Mode=TemplatedParent}}" 
              Style="{StaticResource ExpandCollapseToggleStyle}"/>
<Border x:Name="Bd" Grid.Column="1" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
    <ContentPresenter x:Name="PART_Header" ContentSource="Header" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>

上面紅色部分是我們新增的兩個border,原本的叫Bd的border,我們只保留紫色部分的屬性.

原本的代碼裡面有兩個關於Bd的trigger

我們取名為bd1的border,最開始的Visibility設置的是Hidden,我們替換一下關於Bd的trigger,讓它變成當IsSelected是true的情況下,讓bd1的Visibility變成Visible.

<Trigger Property="IsSelected" Value="true">
    <Setter Property="Visibility" TargetName="bd1" Value="Visible"/>
    <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="Visibility" TargetName="bd1" Value="Visible"/>
    <Setter Property="Background" TargetName="bd1" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/>
    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}}"/>

再運行一下,看一下效果

基本上已經算是成功一半了,但是這個時候,我們的菜單隻有一個有效果,其他的還是原來的樣式,那是因為我們只有一個TreeViewItem使用了我們寫的效果

如果我們每一個TreeViewItem都複製一下這句Style="{DynamicResource TreeViewItemStyle1}" ,是不是顯得很呆,而且這隻是在我們的菜單很少的情況下,如果菜單很多,這個方法就不可行。

所以這裡我們用一個TreeView的ItemContainerStyle來操作一下

        <Style x:Key="treeViewStyle1" TargetType="{x:Type TreeView}" BasedOn="{StaticResource {x:Type TreeView}}">
            <Setter Property="ItemContainerStyle" Value="{StaticResource TreeViewItemStyle1}"/>
        </Style>

我們創建一個類型是TreeView的style,把它的ItemContainerStyle設置成我們之前添加的那個style,然後我們把這個style放到我們的TreeView上

這個時候我們再運行就會發現首級菜單的樣式都實現我們想要的效果了,但是子集菜單還是原來的樣式

我們在代碼裡面添加下麵一個方法

        private void ApplyItemContainerStyle(ItemsControl itemsControl)
        {
            foreach (var item in itemsControl.Items)
            {
                var treeViewItem = item as TreeViewItem;
                if (treeViewItem != null)
                {
                    treeViewItem.Style = treeview1.ItemContainerStyle;
                    ApplyItemContainerStyle(treeViewItem);
                }
            }
        }

然後我們在構造函數裡面把我們的TreeView當做是參數傳進去

這個方法就是把所有的item和item的子項都設置成treeview的ItemContainerStyle;

我們再啟動一下項目,就會發現效果是我們想要的效果了

到這裡其實大部分效果都實現了,基本上也可以向領導交差了;

但是還缺少一個數據可拓展性和一個圖標的功能,我們先看一下數據可拓展性

在平時的項目裡面,一般都會有很多個不同的項目,每個項目可能都有好多個菜單,有的項目還想隱藏某一些菜單,我們總不能所有項目都通過visible屬性來設置吧

特別是報表功能可能會有幾十個,所以我們需要用到一個東西叫數據模板:HierarchicalDataTemplate;

我們先創建一個類

    public class TreeViewModel
    {
        public string Header { get; set; }
        public ObservableCollection<TreeViewModel> Children { get; set; }
    }

然後回到設計器裡面,把我們的代碼改成下麵的代碼

<TreeView Style="{DynamicResource treeViewStyle1}" x:Name="treeview1">
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate DataType="{x:Type local:TreeViewModel}" ItemsSource="{Binding Children}">
            <StackPanel Height="40" Orientation="Horizontal">
                <TextBlock Text="{Binding Header}" VerticalAlignment="Center"/>
            </StackPanel>
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

對比一下紅色部分的綁定,和類的屬性,就能知道這個數據模板怎麼用了.

再到構造函數裡面去添加數據

public ObservableCollection<TreeViewModel> MenuCollection { get; set; }

public MainWindow()
{
    InitializeComponent();


    MenuCollection = new ObservableCollection<TreeViewModel>()
    {
        new TreeViewModel
        {
            Header = "人事部"
        },
        new TreeViewModel
        {
            Header = "技術部",
            Children = new ObservableCollection<TreeViewModel>
            {
                new TreeViewModel { Header = "技術部-1"},
                new TreeViewModel { Header = "技術部-2"},
            }
        },
        new TreeViewModel
        {
            Header = "財務部",
        },
    };

    treeview1.ItemsSource = MenuCollection;
}

註意這兩段標紅的代碼,我們用一個集合MenuCollection模擬一下我們從資料庫或者其他地方查詢出來的菜單集合,然後把它做為數據源給treeview就可以了

再運行一下項目,它就差不多實現我們想要的效果了,現在再去找領導交差,領導還會誇你做的不錯,只是還差一個圖標了,這個就是錦上添花的東西了.

我們百度搜索一下  阿裡ICON,去到官網裡面,創建一個自己的賬號,然後搜索一些自己喜歡的圖標

 把自己喜歡的圖標添加到自己的項目中去,這裡的項目名很重要,我取的是  FatSheep

 在到我的項目裡面去把這個資源文件下載到自己的項目中

 下載下來的文件,我們把ttf尾碼的文件添加到我們的項目裡面去

把它作為資源引入到代碼裡面

<FontFamily x:Key="FatSheep">pack:application:,,,/自己項目的名字;component/Resources/iconfont.ttf#FatSheep</FontFamily>

記得修改一下自己的項目名字,我取的是TreeViewDemo,改成自己的項目名就好了,最後的結尾,是FatSheep,記得改成自己的ICON項目名稱

接著我們在TreeViewModel裡面添加一個Icon屬性

    public class TreeViewModel
    {
        public string Header { get; set; }
        public string Icon { get; set; }
        public ObservableCollection<TreeViewModel> Children { get; set; }
    }

然後我們在數據源裡面添加一下數據

MenuCollection = new ObservableCollection<TreeViewModel>()
{
    new TreeViewModel
    {
        Header = "人事部",
        Icon = "\ue71c"
    },
    new TreeViewModel
    {
        Header = "技術部",
        Icon = "\ue71c",
        Children = new ObservableCollection<TreeViewModel>
        {
            new TreeViewModel { Header = "技術部-1", Icon="\ue71c"},
            new TreeViewModel { Header = "技術部-2" , Icon="\ue71c"},
        }
    },
    new TreeViewModel
    {
        Header = "財務部",
        Icon = "\ue71c"
    },
};

設計器裡面添加一下顯示部分的代碼

<TreeView Style="{StaticResource treeViewStyle1}" x:Name="treeView1" BorderThickness="0,0,1,0" Grid.Column="1">
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate DataType="{x:Type local:TreeViewModel}" ItemsSource="{Binding Children}">
            <StackPanel Height="40" Orientation="Horizontal">
                <TextBlock Text="{Binding Icon}" VerticalAlignment="Center" FontFamily="{StaticResource FatSheep}" Margin="0,0,5,0"/>
                <TextBlock Text="{Binding Header}" VerticalAlignment="Center"/>
            </StackPanel>
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

再啟動項目,功能就完成了

這個笑臉是怎麼來的了

那是因為我自己的項目裡面添加了一個笑臉

我們複製一下這個代碼,   &#xe71c;  我們把它改成 \ue71c,這是一個轉義字元,就這樣我們就能添加如何自己喜歡的圖標了。

 

 

項目github地址:bearhanQ/WPFFramework: Share some experience (github.com)

QQ技術交流群:332035933;

歡迎進群討論問題,不論是winform,還是wpf,還是.net core的,還有很多萌妹.

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ZY樹洞 前言 ZY樹洞是一個基於.NET Core開發的簡單的評論系統,主要用於大家分享自己心中的感悟、經驗、心得、想法等。 好了,不賣關子了,這個項目其實是上班無聊的時候寫的,為什麼要寫這個項目呢?因為我單純的想吐槽一下工作中的不滿而已。 項目介紹 項目很簡單,主要功能就是提供一個簡單的評論系統 ...
  • 簡介 在現代微服務架構中,服務發現(Service Discovery)是一項關鍵功能。它允許微服務動態地找到彼此,而無需依賴硬編碼的地址。以前如果你搜 .NET Service Discovery,大概率會搜到一大堆 Eureka,Consul 等的文章。現在微軟為我們帶來了一個官方的包:Micr ...
  • 1.下載 Protocol Buffers 編譯器(protoc) 前往 Protocol Buffers GitHub Releases 頁面。在 "Assets" 下找到適合您系統的壓縮文件,通常為 protoc-{version}-win32.zip 或 protoc-{version}-wi ...
  • 在 C# 中使用 RabbitMQ 通過簡訊發送重置後的密碼到用戶的手機號上,你可以按照以下步驟進行 1.安裝 RabbitMQ 客戶端庫 首先,確保你已經安裝了 RabbitMQ 客戶端庫。你可以通過 NuGet 包管理器來安裝: dotnet add package RabbitMQ.Clien ...
  • 在軟體行業,經常會聽到一句話“文不如表,表不如圖”說明瞭圖形在軟體應用中的重要性。同樣在WPF開發中,為了程式美觀或者業務需要,經常會用到各種個樣的圖形。今天以一些簡單的小例子,簡述WPF開發中幾何圖形(Geometry)相關內容,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 之前寫過兩篇關於Roslyn源生成器生成源代碼的用例,今天使用Roslyn的代碼修複器CodeFixProvider實現一個cs文件頭部註釋的功能, 代碼修複器會同時涉及到CodeFixProvider和DiagnosticAnalyzer, 實現FileHeaderAnalyzer 首先我們知道修 ...
  • 本文為大家介紹下.NET解壓/壓縮zip文件。雖然解壓縮不是啥核心技術,但壓縮性能以及進度處理還是需要關註下,針對使用較多的zip開源組件驗證,給大家提供個技術選型參考 之前在《.NET WebSocket高併發通信阻塞問題 - 唐宋元明清2188 - 博客園 (cnblogs.com)》講過,團隊 ...
  • 1. 生成式 AI 簡介 https://imp.i384100.net/LXYmq3 2. Python 語言 https://imp.i384100.net/5gmXXo 3. 統計和 R https://youtu.be/ANMuuq502rE?si=hw9GT6JVzMhRvBbF 4. 數 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...