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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...