<Window x:Class="WpfApp1.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:WpfApp1" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Window.Resources> <local:MyColorConverter x:Key="cc"></local:MyColorConverter> </Window.Resources> <TabControl> <TabItem Header="文本反序列化"> <Grid Margin="5"> <Grid.ColumnDefinitions> <ColumnDefinition></ColumnDefinition> <ColumnDefinition Width="Auto"></ColumnDefinition> <ColumnDefinition></ColumnDefinition> <ColumnDefinition Width="Auto"></ColumnDefinition> </Grid.ColumnDefinitions> <DockPanel> <TextBlock Text="原始文本:" DockPanel.Dock="Top"></TextBlock> <TextBox x:Name="tb1" Background="Transparent" Foreground="Gray" TextWrapping="Wrap" /> </DockPanel> <Button Content="->->" Margin="5" Grid.Column="1" Height="35" Click="ButtonBase_OnClick" /> <DockPanel Grid.Column="2"> <TextBox Text="解析后:" DockPanel.Dock="Top"></TextBox> <TreeView x:Name="tv" Background="Transparent" Grid.Column="2"> <TreeView.ItemContainerStyle> <Style TargetType="TreeViewItem"> <Setter Property="IsExpanded" Value="True"></Setter> </Style> </TreeView.ItemContainerStyle> <TreeView.ItemTemplate> <HierarchicalDataTemplate ItemsSource="{Binding Children}"> <StackPanel Orientation="Horizontal" Margin="0 2"> <TextBox Foreground="{Binding Level,Converter={StaticResource cc}}" Text="{Binding Key}" MinWidth="160"></TextBox> <TextBox Text="{Binding Value}" MinWidth="160" Foreground="Gray" Margin="5 0 0 0"></TextBox> </StackPanel> </HierarchicalDataTemplate> </TreeView.ItemTemplate> </TreeView> </DockPanel> <Button Content="导出结果到csv" Grid.Column="3" Height="35" Click="exportClick"></Button> </Grid> </TabItem> </TabControl> </Window>
using System; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Windows; using Hprose.IO; using Microsoft.Win32; namespace WpfApp1 { /// <summary> /// MainWindow.xaml 的交互逻辑 /// </summary> public partial class MainWindow : Window { private static Dictionary<string, string> s = new Dictionary<string, string>(); private static string msg = ""; public MainWindow() { InitializeComponent(); } /// <summary> /// 解析【类】 /// </summary> /// <param name="str_obj_dict"></param> /// <param name="level"></param> /// <returns></returns> private static List<SimpleKeyValuePair> ParseStringObjDict(Dictionary<string, object> str_obj_dict, int level) { var mm = new List<SimpleKeyValuePair>(); foreach (var o in str_obj_dict) //【子序列】 if (o.Value is IEnumerable<object> d) { var sp = new SimpleKeyValuePair(); sp.Key = o.Key; sp.Value = "【子集序列】" + "个数" + d.Count(); sp.Children = ParseObjectList(d, sp.Key, level); sp.Level = level; mm.Add(sp); } //【类】 else if (o.Value is Dictionary<string, object> dict) { var sp = new SimpleKeyValuePair(); sp.Key = o.Key; sp.Value = "【类】"; sp.Children = ParseStringObjDict(dict, level); sp.Level = level; mm.Add(sp); } //【单个字段】 else { var sp = new SimpleKeyValuePair(); sp.Key = o.Key; sp.Value = o.Value?.ToString(); sp.Level = level; mm.Add(sp); } return mm; } /// <summary> /// 解析【序列,子集】 /// </summary> /// <param name="dd"></param> /// <param name="parentName"></param> /// <param name="level"></param> /// <returns></returns> private static List<SimpleKeyValuePair> ParseObjectList(IEnumerable<object> dd, string parentName, int level) { var childrenList = new List<SimpleKeyValuePair>(); var i = 0; level++; foreach (var o in dd) { var tp = o.GetType(); var child = new SimpleKeyValuePair {Key = parentName + "的【子集】" + i++, Value = "【新的类】", Level = level}; if (o is Dictionary<string, object> d) { childrenList.Add(child); child.Children = ParseStringObjDict(d, level); } } return childrenList; } private void ButtonBase_OnClick(object sender, RoutedEventArgs e) { try { var bts = Encoding.UTF8.GetBytes(tb1.Text); var str_obj_dict = HproseFormatter.Unserialize<Dictionary<string, object>>(bts); var result = ParseStringObjDict(str_obj_dict, 0); tv.ItemsSource = null; tv.ItemsSource = result; } catch (Exception exception) { MessageBox.Show(exception.Message); } } private void exportClick(object sender, RoutedEventArgs e) { var result = "key,value "; if (tv.ItemsSource is List<SimpleKeyValuePair> li) result += MakeString(li, 0); var sfd = new SaveFileDialog(); sfd.Filter = ".csv|*.csv|.txt|*.txt"; var ok = sfd.ShowDialog(this); if (ok == true) if (!string.IsNullOrEmpty(sfd.FileName)) SimpleLogger.Log(sfd.FileName, result); } private string MakeString(List<SimpleKeyValuePair> li, int quoteTimes) { var result = ""; li.ForEach(x => { result = result + " " + string.Join(",", Enumerable.Range(0, quoteTimes).Select(y => "").ToArray()) + GetSafeStr(x.Key) + "," + GetSafeStr(x.Value); if (x.Children != null && x.Children.Count > 0) { var newTime = quoteTimes + 2; result = result + MakeString(x.Children, newTime); } } ); return result; } private string GetSafeStr(string x) { if (x == null) return ""; return """ + x + """; } } public static class SimpleLogger { private static readonly object locker = new object(); public static void Log(string file, string msg) { lock (locker) { var fs = new FileStream(file, FileMode.OpenOrCreate); var sw = new StreamWriter(fs, Encoding.Default); sw.WriteLine(msg); sw.Close(); } } } public class SimpleKeyValuePair : INotifyPropertyChanged { public string Key { get; set; } public string Value { get; set; } public List<SimpleKeyValuePair> Children { get; set; } = new List<SimpleKeyValuePair>(); public int Level { get; set; } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }
using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using System.Windows.Data; using System.Windows.Media; namespace WpfApp1 { public class MyColorConverter : IValueConverter { static List<SolidColorBrush> _solid=new List<SolidColorBrush>(){Brushes.Red,Brushes.Blue,Brushes.Green,Brushes.Brown,Brushes.Magenta,Brushes.Orange,Brushes.Cyan}; public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is int level) { return _solid[level]; } return null; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } }
效果图