WPF TreeView HierarchicalDataTemplate, parse xml via traverse in XmlElement

public class TreeNodeModel
{
    public string TreeNodeName { get; set; }
    public string TreeNodeValue { get; set; }
    public List<TreeNodeModel> TreeNodeChildren { get; set; }

}

 private TreeNodeModel ParseXmlRecursively(XmlElement xElem)
 {
     TreeNodeModel nodeModel = new TreeNodeModel()
     {
         TreeNodeName=xElem.Name,
         TreeNodeChildren = new List<TreeNodeModel>()
     };

     foreach(XmlAttribute attr in xElem.Attributes)
     {
         nodeModel.TreeNodeChildren.Add(new TreeNodeModel()
         {
             TreeNodeName=attr.Name,
             TreeNodeValue=$" = {attr.Value}"
         });
     }

     foreach(XmlNode child in xElem.ChildNodes)
     {
         if (child is XmlElement childElem)
         {
             nodeModel.TreeNodeChildren.Add(ParseXmlRecursively(childElem));
         }
     }
     return nodeModel;
 }


    <HierarchicalDataTemplate DataType="{x:Type local:TreeNodeModel}"
                              ItemsSource="{Binding TreeNodeChildren}"
                              x:Key="TreeViewItemDataTemplate">
        <Grid>
            <Grid.Resources>
                <Style TargetType="TextBlock" BasedOn="{StaticResource TbkStyle}"/>
            </Grid.Resources>
            <Grid.ColumnDefinitions>
                <ColumnDefinition SharedSizeGroup="NameGroup"/>
                <ColumnDefinition SharedSizeGroup="ValueGroup"/>
            </Grid.ColumnDefinitions>
            <TextBlock Text="{Binding TreeNodeName}" Grid.Column="0"/>
            <TextBlock Text="{Binding TreeNodeValue}" Grid.Column="1"/>
        </Grid>
    </HierarchicalDataTemplate>
    
</Window.Resources>
<Grid>
    <TreeView ItemsSource="{Binding TreeNodes}"
              ItemTemplate="{StaticResource TreeViewItemDataTemplate}"
              Grid.IsSharedSizeScope="True"/>
</Grid>

 

 

 

 

//xaml
<Window x:Class="WpfApp7.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:WpfApp7"
        mc:Ignorable="d"
        Title="MainWindow" WindowState="Maximized">
    <Window.DataContext>
        <local:MainVM/>
    </Window.DataContext>

    <Window.Resources>
        <Style TargetType="TextBlock" x:Key="TbkStyle">
            <Setter Property="FontSize" Value="30"/>
            <Setter Property="FontWeight" Value="Normal"/>
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Foreground" Value="Red"/>
                </Trigger>
            </Style.Triggers>
        </Style>

        <Style TargetType="TreeViewItem">
            <Setter Property="IsExpanded" Value="True"/>
        </Style>
 

        <HierarchicalDataTemplate DataType="{x:Type local:TreeNodeModel}"
                                  ItemsSource="{Binding TreeNodeChildren}"
                                  x:Key="TreeViewItemDataTemplate">
            <Grid>
                <Grid.Resources>
                    <Style TargetType="TextBlock" BasedOn="{StaticResource TbkStyle}"/>
                </Grid.Resources>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition SharedSizeGroup="NameGroup"/>
                    <ColumnDefinition SharedSizeGroup="ValueGroup"/>
                </Grid.ColumnDefinitions>
                <TextBlock Text="{Binding TreeNodeName}" Grid.Column="0"/>
                <TextBlock Text="{Binding TreeNodeValue}" Grid.Column="1"/>
            </Grid>
        </HierarchicalDataTemplate>
        
    </Window.Resources>
    <Grid>
        <TreeView ItemsSource="{Binding TreeNodes}"
                  ItemTemplate="{StaticResource TreeViewItemDataTemplate}"
                  Grid.IsSharedSizeScope="True"/>
    </Grid>
</Window>


//cs
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Net.Http;
using System.Runtime.CompilerServices;
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;
using System.Xml;

namespace WpfApp7
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.Closed += MainWindow_Closed;
        }

        private void MainWindow_Closed(object? sender, EventArgs e)
        {
            var vm = this.DataContext as MainVM;
            if(vm!=null)
            {
                vm.Dispose();
            }
        }
    }

    public class MainVM : INotifyPropertyChanged, IDisposable
    {
        public event PropertyChangedEventHandler? PropertyChanged;
        private bool _isDisposed = false;
        private HttpClient _client = new HttpClient()
        {
            Timeout = TimeSpan.FromMinutes(60)
        };

        private CancellationTokenSource _cts = new CancellationTokenSource();

        string originalUrl = "http://localhost:57995/BookService.svc/getbooks?cnt=";
        public MainVM()
        {
            if (!DesignerProperties.GetIsInDesignMode(new DependencyObject()))
            {
                _ = ParseXmlAsync();
            }
        }

        private async Task ParseXmlAsync()
        {
            string xmlFile = @"../../../Web.config";
            if(File.Exists(xmlFile))
            {
                try
                {
                    string xmlStr = File.ReadAllText(xmlFile);
                    XmlDocument xmlDoc = new XmlDocument();
                    xmlDoc.LoadXml(xmlStr);
                    TreeNodeModel node = ParseXmlRecursively(xmlDoc.DocumentElement);

                    await Application.Current?.Dispatcher?.InvokeAsync(() =>
                    {
                        TreeNodes = new ObservableCollection<TreeNodeModel>();
                        TreeNodes.Add(node);
                    });
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex?.Message);   
                }               
            }
        }

        private TreeNodeModel ParseXmlRecursively(XmlElement xElem)
        {
            TreeNodeModel nodeModel = new TreeNodeModel()
            {
                TreeNodeName=xElem.Name,
                TreeNodeChildren = new List<TreeNodeModel>()
            };

            foreach(XmlAttribute attr in xElem.Attributes)
            {
                nodeModel.TreeNodeChildren.Add(new TreeNodeModel()
                {
                    TreeNodeName=attr.Name,
                    TreeNodeValue=$" = {attr.Value}"
                });
            }

            foreach(XmlNode child in xElem.ChildNodes)
            {
                if (child is XmlElement childElem)
                {
                    nodeModel.TreeNodeChildren.Add(ParseXmlRecursively(childElem));
                }
            }
            return nodeModel;
        }

        private ObservableCollection<TreeNodeModel> treeNodes;
        public ObservableCollection<TreeNodeModel> TreeNodes
        {
            get
            {
                return treeNodes;
            }
            set
            {
                if(value!=treeNodes)
                {
                    treeNodes = value;
                    OnPropertyChanged();
                }
            }
        }

        private void OnPropertyChanged([CallerMemberName] string propName = "")
        {
            var handler = PropertyChanged;
            if (handler == null)
            {
                return;
            }
            handler?.Invoke(this, new PropertyChangedEventArgs(propName));
        }

        public void Dispose()
        {
            throw new NotImplementedException();
        }

        protected virtual void Dispose(bool disposing)
        {
            if (_isDisposed)
            {
                return;
            }

            if (disposing)
            {
                _client = null;
                _cts = null;
            }
        }
    }


    public class TreeNodeModel
    {
        public string TreeNodeName { get; set; }
        public string TreeNodeValue { get; set; }
        public List<TreeNodeModel> TreeNodeChildren { get; set; }

    }
}

 

 

 

image

 

 

 

 

 

 

image

 

 

<?xml version="1.0"?>
<configuration>

  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.7.2" />
    <httpRuntime targetFramework="4.7.2"/>
  </system.web>
  <system.serviceModel>
      <bindings>
          <webHttpBinding>
              <binding name="BookServiceWebHttpBinding"
                       openTimeout="01:00:00"
                       closeTimeout="01:00:00"
                       sendTimeout="01:00:00"
                       receiveTimeout="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="WcfService3.BookService"
                   behaviorConfiguration="BookServiceBehavior">
              <endpoint address=""
                        binding="webHttpBinding"
                        contract="WcfService3.IBookService"
                        behaviorConfiguration="BookServiceEndPointBehavior"
                        bindingConfiguration="BookServiceWebHttpBinding"/>
          </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>

 

posted @ 2026-07-26 21:59  FredGrit  阅读(2)  评论(0)    收藏  举报