WPF TreeView HierarchicalDataTemplate DataTemplate, Enum get enum name

public enum BookCategory
{
    Science,
    Technology,
    Engineer,
    Math,
    Arts
}

static Array values = Enum.GetValues(typeof(BookCategory));
static Random rnd = new Random();

int rndIdx = rnd.Next(0, values.Length);
string categoryName = Enum.GetName(typeof(BookCategory), rndIdx);
BookCategoryName = categoryName

 

 

Install-Package CommunityToolkit.mvvm
Install-Package Newtonsoft.json

 

 

<Window x:Class="WpfApp13.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp13"
        mc:Ignorable="d"
        Title="MainWindow" WindowState="Maximized">

    <Window.DataContext>
        <local:MainVM/>
    </Window.DataContext>
    <Window.Resources>
        <local:LenConverter x:Key="LenConverter"/>
        
        <HierarchicalDataTemplate DataType="{x:Type local:CategoryNode}"
                                  ItemsSource="{Binding Books}">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding CategoryName}" FontWeight="Bold"
                               FontSize="30">
                </TextBlock>
                <TextBlock Text="(" Margin="5,0,0,0" Foreground="Gray"/>
                <TextBlock Text="{Binding BookCount}" Foreground="Gray"/>
                <TextBlock Text=")" Foreground="Gray"/>
            </StackPanel>
        </HierarchicalDataTemplate>

        <DataTemplate DataType="{x:Type local:Book}">
            <Border BorderBrush="LightBlue" BorderThickness="5" Margin="2,2,2,2"
                        Width="{Binding Source={x:Static SystemParameters.FullPrimaryScreenWidth},
                    Converter={StaticResource LenConverter},ConverterParameter=100}"
                        Height="{Binding Source={x:Static SystemParameters.FullPrimaryScreenHeight},
                    Converter={StaticResource LenConverter},ConverterParameter=2}">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition/>
                        <RowDefinition/>
                        <RowDefinition/>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition/>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition/>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>

                    <Grid.Resources>
                        <Style TargetType="TextBlock">
                            <Setter Property="FontSize" Value="30"/>
                            <Setter Property="Foreground" Value="Black"/>
                            <Style.Triggers>
                                <Trigger Property="IsMouseOver" Value="True">
                                    <Setter Property="FontSize" Value="50"/>
                                    <Setter Property="Foreground" Value="Red"/>
                                </Trigger>
                            </Style.Triggers>
                        </Style>
                    </Grid.Resources>
                    <TextBlock Text="Id:" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Right"/>
                    <TextBlock Text="{Binding Id}" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Left"/>
                    <TextBlock Text="Name:" Grid.Row="0" Grid.Column="2" HorizontalAlignment="Right"/>
                    <TextBlock Text="{Binding Name}" Grid.Row="0" Grid.Column="3" HorizontalAlignment="Left"/>
                    <TextBlock Text="ISBN:" Grid.Row="0" Grid.Column="4" HorizontalAlignment="Right"/>
                    <TextBlock Text="{Binding ISBN}" Grid.Row="0" Grid.Column="5" HorizontalAlignment="Left"/>
                    <TextBlock Text="Author:" Grid.Row="1" Grid.Column="0" HorizontalAlignment="Right"/>
                    <TextBlock Text="{Binding Author}" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left"/>
                    <TextBlock Text="Comment:" Grid.Row="1" Grid.Column="2" HorizontalAlignment="Right"/>
                    <TextBlock Text="{Binding Comment}" Grid.Row="1" Grid.Column="3" HorizontalAlignment="Left"/>
                    <TextBlock Text="Content:" Grid.Row="1" Grid.Column="4" HorizontalAlignment="Right"/>
                    <TextBlock Text="{Binding Content}"  Grid.Row="1" Grid.Column="5" HorizontalAlignment="Left"/>
                    <TextBlock Text="Summary:" Grid.Row="2" Grid.Column="0" HorizontalAlignment="Right"/>
                    <TextBlock Text="{Binding Summary}" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Left"/>
                    <TextBlock Text="Title:" Grid.Row="2" Grid.Column="2" HorizontalAlignment="Right"/>
                    <TextBlock Text="{Binding Title}" Grid.Row="2" Grid.Column="3" HorizontalAlignment="Left"/>
                    <TextBlock Text="Title:" Grid.Row="2" Grid.Column="4" HorizontalAlignment="Right"/>
                    <TextBlock Text="{Binding Topic}" Grid.Row="2" Grid.Column="5" HorizontalAlignment="Left"/>
                </Grid>
            </Border>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <TreeView ItemsSource="{Binding CategoryNodes}"
                  BorderThickness="1"
                  BorderBrush="LightGray"
                  ScrollViewer.HorizontalScrollBarVisibility="Auto"
                  ScrollViewer.VerticalScrollBarVisibility="Auto">
            <TreeView.ItemContainerStyle>
                <Style TargetType="TreeViewItem">
                    <Setter Property="IsExpanded" Value="False"/>
                    <Setter Property="FontSize" Value="20"/>
                </Style>
            </TreeView.ItemContainerStyle>
        </TreeView>
    </Grid>
</Window>

 

WCF generate data as service

//D:\C\WcfService6\WcfService6\IBookService.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace WcfService6
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IBookService" in both code and config file together.
    [ServiceContract]
    public interface IBookService
    {
        [OperationContract]
        [WebGet(UriTemplate="/getbookslist?cnt={cnt}",RequestFormat =WebMessageFormat.Json,
            ResponseFormat =WebMessageFormat.Json)]
        List<Book> GetBooksList(long cnt);
    }

    public class Book
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public string BookCategoryName { get; set; }
        public string ISBN { get; set; }
        public string Author { get; set; }
        public string Comment { get; set; }
        public string Content { get; set; }
        public string Summary { get; set; }
        public string Title { get; set; }
        public string Topic { get; set; }
        
    }

    public enum BookCategory
    {
        Science,
        Technology,
        Engineer,
        Math,
        Arts
    }
}


//D:\C\WcfService6\WcfService6\BookService.svc.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.Threading;

namespace WcfService6
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "BookService" in code, svc and config file together.
    // NOTE: In order to launch WCF Test Client for testing this service, please select BookService.svc or BookService.svc.cs at the Solution Explorer and start debugging.
    public class BookService : IBookService
    {
        private static long id = 1;
        static Random rnd = new Random();
        static Array values = Enum.GetValues(typeof(BookCategory));
        private static (long,long) GetStartEnd(long cnt)
        {
            long end=Interlocked.Add(ref id, cnt);
            long start = end - cnt;
            return (start,end);
        }
        
        public List<Book> GetBooksList(long cnt)
        {
            var (start, end) = GetStartEnd(cnt);
            List<Book> bksList = new List<Book>();
            for(long i=start;i<end;i++)
            {
                int rndIdx = rnd.Next(0, values.Length);
                string categoryName = Enum.GetName(typeof(BookCategory), rndIdx);
                bksList.Add(new Book()
                {
                    Id = i,
                    Name = $"Name_{i}",
                    ISBN = $"ISBN_{i}_{Guid.NewGuid():N}",
                    Author = $"Author_{i}",
                    Comment = $"Comment_{i}",
                    Content = $"Content_{i}",
                    Summary = $"Summary_{i}",
                    Title = $"Title_{i}",
                    Topic = $"Topic_{i}",
                    BookCategoryName = categoryName
                });
            }
            return bksList;
        }
    }
}

//D:\C\WcfService6\WcfService6\Web.config
<?xml version="1.0"?>
<configuration>

    <appSettings>
        <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
    </appSettings>
    <system.web>
        <compilation debug="true" targetFramework="4.8" />
        <httpRuntime targetFramework="4.8"/>
    </system.web>
    <system.serviceModel>
        <bindings>
            <webHttpBinding>
                <binding name="BookServiceWebHttpBinding"
                         openTimeout="01:00:00"
                         closeTimeout="01:00:00"
                          receiveTimeout="01:00:00"
                          sendTimeout="01:00:00"
                          maxBufferPoolSize="2147483647"
                          maxBufferSize="2147483647"
                          maxReceivedMessageSize="2147483647">
                    <readerQuotas maxArrayLength="2147483647"
                                   maxBytesPerRead="2147483647"
                                   maxDepth="2147483647"
                                   maxNameTableCharCount="2147483647"
                                   maxStringContentLength="2147483647"/>
                </binding>
            </webHttpBinding>
        </bindings>
        <behaviors>
            <serviceBehaviors>
                <behavior name="BookServiceBehavior">
                    <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
                    <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
                    <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
                    <serviceDebug includeExceptionDetailInFaults="false"/>
                </behavior>
            </serviceBehaviors>
            <endpointBehaviors>
                <behavior name="BookServiceEndpointBehavior">
                    <webHttp/>
                </behavior>
            </endpointBehaviors>
        </behaviors>
        <protocolMapping>
            <add binding="basicHttpsBinding" scheme="https" />
        </protocolMapping>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
        <services>
            <service name="WcfService6.BookService"
                     behaviorConfiguration="BookServiceBehavior">
                <endpoint address=""
                          binding="webHttpBinding"
                          contract="WcfService6.IBookService"
                          bindingName="BookServiceWebHttpBinding"
                          behaviorConfiguration="BookServiceEndpointBehavior"/>                          
            </service>
        </services>
    </system.serviceModel>
    <system.webServer>
        <modules runAllManagedModulesForAllRequests="true"/>
        <!--
        To browse web app root directory during debugging, set the value below to true.
        Set to false before deployment to avoid disclosing web app folder information.
      -->
        <directoryBrowse enabled="true"/>
    </system.webServer>

</configuration>

 

http://localhost:51906/BookService.svc/getbookslist?cnt=1000

 

 

 

 

image

 

 

//WPF

//D:\C\WpfApp13\WpfApp13\MainWindow.xaml
<Window x:Class="WpfApp13.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp13"
        mc:Ignorable="d"
        Title="MainWindow" WindowState="Maximized">

    <Window.DataContext>
        <local:MainVM/>
    </Window.DataContext>
    <Window.Resources>
        <local:LenConverter x:Key="LenConverter"/>
        
        <HierarchicalDataTemplate DataType="{x:Type local:CategoryNode}"
                                  ItemsSource="{Binding Books}">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding CategoryName}" FontWeight="Bold"
                               FontSize="30">
                </TextBlock>
                <TextBlock Text="(" Margin="5,0,0,0" Foreground="Gray"/>
                <TextBlock Text="{Binding BookCount}" Foreground="Gray"/>
                <TextBlock Text=")" Foreground="Gray"/>
            </StackPanel>
        </HierarchicalDataTemplate>

        <DataTemplate DataType="{x:Type local:Book}">
            <Border BorderBrush="LightBlue" BorderThickness="5" Margin="2,2,2,2"
                        Width="{Binding Source={x:Static SystemParameters.FullPrimaryScreenWidth},
                    Converter={StaticResource LenConverter},ConverterParameter=100}"
                        Height="{Binding Source={x:Static SystemParameters.FullPrimaryScreenHeight},
                    Converter={StaticResource LenConverter},ConverterParameter=2}">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition/>
                        <RowDefinition/>
                        <RowDefinition/>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition/>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition/>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>

                    <Grid.Resources>
                        <Style TargetType="TextBlock">
                            <Setter Property="FontSize" Value="30"/>
                            <Setter Property="Foreground" Value="Black"/>
                            <Style.Triggers>
                                <Trigger Property="IsMouseOver" Value="True">
                                    <Setter Property="FontSize" Value="50"/>
                                    <Setter Property="Foreground" Value="Red"/>
                                </Trigger>
                            </Style.Triggers>
                        </Style>
                    </Grid.Resources>
                    <TextBlock Text="Id:" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Right"/>
                    <TextBlock Text="{Binding Id}" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Left"/>
                    <TextBlock Text="Name:" Grid.Row="0" Grid.Column="2" HorizontalAlignment="Right"/>
                    <TextBlock Text="{Binding Name}" Grid.Row="0" Grid.Column="3" HorizontalAlignment="Left"/>
                    <TextBlock Text="ISBN:" Grid.Row="0" Grid.Column="4" HorizontalAlignment="Right"/>
                    <TextBlock Text="{Binding ISBN}" Grid.Row="0" Grid.Column="5" HorizontalAlignment="Left"/>
                    <TextBlock Text="Author:" Grid.Row="1" Grid.Column="0" HorizontalAlignment="Right"/>
                    <TextBlock Text="{Binding Author}" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left"/>
                    <TextBlock Text="Comment:" Grid.Row="1" Grid.Column="2" HorizontalAlignment="Right"/>
                    <TextBlock Text="{Binding Comment}" Grid.Row="1" Grid.Column="3" HorizontalAlignment="Left"/>
                    <TextBlock Text="Content:" Grid.Row="1" Grid.Column="4" HorizontalAlignment="Right"/>
                    <TextBlock Text="{Binding Content}"  Grid.Row="1" Grid.Column="5" HorizontalAlignment="Left"/>
                    <TextBlock Text="Summary:" Grid.Row="2" Grid.Column="0" HorizontalAlignment="Right"/>
                    <TextBlock Text="{Binding Summary}" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Left"/>
                    <TextBlock Text="Title:" Grid.Row="2" Grid.Column="2" HorizontalAlignment="Right"/>
                    <TextBlock Text="{Binding Title}" Grid.Row="2" Grid.Column="3" HorizontalAlignment="Left"/>
                    <TextBlock Text="Title:" Grid.Row="2" Grid.Column="4" HorizontalAlignment="Right"/>
                    <TextBlock Text="{Binding Topic}" Grid.Row="2" Grid.Column="5" HorizontalAlignment="Left"/>
                </Grid>
            </Border>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <TreeView ItemsSource="{Binding CategoryNodes}"
                  BorderThickness="1"
                  BorderBrush="LightGray"
                  ScrollViewer.HorizontalScrollBarVisibility="Auto"
                  ScrollViewer.VerticalScrollBarVisibility="Auto">
            <TreeView.ItemContainerStyle>
                <Style TargetType="TreeViewItem">
                    <Setter Property="IsExpanded" Value="False"/>
                    <Setter Property="FontSize" Value="20"/>
                </Style>
            </TreeView.ItemContainerStyle>
        </TreeView>
    </Grid>
</Window>


//D:\C\WpfApp13\WpfApp13\MainWindow.xaml.cs
using CommunityToolkit.Mvvm.ComponentModel;
using Newtonsoft.Json;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Net.Http;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApp13
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }

    public partial class MainVM : ObservableObject
    {
        [ObservableProperty]
        private ObservableCollection<CategoryNode> categoryNodes;
        static HttpClient client;
        string originUrl = "http://localhost:51906/BookService.svc/getbookslist?cnt=";
        public MainVM()
        {
            client = new HttpClient();
            _ = InitDataAsync();
        }

        private async Task InitDataAsync(long cnt = 100)
        {
            string requestUrl = $"{originUrl}{cnt}";
            string jsonStr = await client.GetStringAsync(requestUrl);
            if (!string.IsNullOrWhiteSpace(jsonStr))
            {
                var bksList = JsonConvert.DeserializeObject<List<Book>>(jsonStr);
                if (bksList != null && bksList.Any())
                {
                    var groupedBooks = bksList.GroupBy(x => x.BookCategoryName)
                    .OrderBy(g => g.Key)
                    .Select(g => new CategoryNode
                    {
                        CategoryName = g.Key,
                        Books = new ObservableCollection<Book>(g.OrderBy(x => x.Id))
                    });
                    CategoryNodes = new ObservableCollection<CategoryNode>(groupedBooks);
                }
            }
        }
    }

    public class Book
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public string BookCategoryName { get; set; }
        public string ISBN { get; set; }
        public string Author { get; set; }
        public string Comment { get; set; }
        public string Content { get; set; }
        public string Summary { get; set; }
        public string Title { get; set; }
        public string Topic { get; set; }
    }


    public class CategoryNode
    {
        public string CategoryName { get; set; }
        public ObservableCollection<Book> Books { get; set; }
        public int BookCount => Books?.Count ?? 0;

        public CategoryNode()
        {
            Books = new ObservableCollection<Book>();
        }
    }

    public class LenConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            double dValue = 0;
            double dPara = 1;
            if (double.TryParse(value?.ToString(), out dValue) &&
                double.TryParse(parameter?.ToString(), out dPara))
            {
                if(dPara == 2.0)
                {
                    return dValue / dPara;
                }
                return dValue - dPara;
            }
            return 0;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

image

 

 

 

 

image

 

 

 

 

 

image

 

 

 

image

 

posted @ 2026-07-05 22:02  FredGrit  阅读(7)  评论(0)    收藏  举报