算法之递归(4)- 应用
最近带着几个在做一个项目,UI层面用的是WPF。之前很少深入的接触WPF,不过接触后,发现WPF的却是很强大。
至少在界面设计上的用户体验较WinForm有了大幅提升。
项目中需要通用化几个样式,并将样式赋值给相应的控件。控件是根据配置文件动态生成的,配置文件是xml格式的层次化较多的结构。所以在动态生成的过程中采用了递归的方式来实现。
下面是一个模拟实例。
目标:
将程序集“PresentationFramework"的所有类型添加到TreeView里面,如果一个类型存在基类行,那么先加入基类型,以此类推。
实践:
1. 创建一个WPF应用程序,添加一个xml文件,放在工程的根目录下即可。(不用放在outputdir下面)。
2. 在此xml文件里,添加如下代码并保存。
<Style xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:l="clr-namespace:System.Windows.Controls;assembly:PresentationFramework" TargetType="{x:Type TypeName=TreeViewItem}"> <Setter Property="Foreground" Value="Yellow" /> <Setter Property="FontFamily" Value="Comic Sans MS" /> <Setter Property="FontSize" Value="18" /> <Style.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="Background" Value="DarkBlue" /> </Trigger> </Style.Triggers> </Style>
3. 在MainWindow的cs文件中创建一个style解析器。代码如下。
private void StyleParser() { using (FileStream fileStream = new FileStream(this.stylePath, FileMode.Open, FileAccess.Read)) { this.myStyle = (Style)XamlReader.Load(fileStream); } }
4. 将”PresentationFramework"所有的类型以递归的形式添加到TreeView里面。
(1) 定义递归算法。
private void AppendItem(ItemsControl ctrl, Type type) { if (type.BaseType == null) return; TreeViewItem myTreeViewItem = new TreeViewItem(){ Header = type.FullName, Style = this.myStyle}; ctrl.Items.Add(myTreeViewItem); AppendItem(myTreeViewItem, type.BaseType); }
(2) 初始化TreeView,并调用AppendItem方法。
private void Window_Loaded_1(object sender, RoutedEventArgs e) { ReLayout(); myTreeView.Background = Brushes.SeaGreen; myTreeView.HorizontalAlignment = System.Windows.HorizontalAlignment.Left; myTreeView.VerticalAlignment = System.Windows.VerticalAlignment.Top; myTreeView.Margin = new Thickness(5, 5, 0, 0); this.mainGrid.Children.Add(myTreeView); var asm = Assembly.GetAssembly(typeof(TreeViewItem)); foreach (var type in asm.ExportedTypes) { var node = new TreeViewItem() { Header = type.FullName, Style = this.myStyle }; myTreeView.Items.Add(node); AppendItem(node, type); } }
5. 定义一个ReLayout方法,用来调整TreeView控件在主窗体中的布局。并在“SizeChanged",”StateChanged“实践中调用该方法。
private void ReLayout() { if (this.ActualHeight < 500) return; if (this.ActualWidth < 500) return; myTreeView.Height = this.ActualHeight - 50; myTreeView.Width = this.ActualWidth / 2; }
6. 运行,效果如下。
完整代码如下。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; 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.Windows.Markup; using System.IO; using System.Reflection; namespace WpfApplication8 { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { private Style myStyle; private string stylePath = "..\\..\\CustomizedStyle.xml"; private TreeView myTreeView = new TreeView(); public MainWindow() { InitializeComponent(); this.StyleParser(); } private void StyleParser() { using (FileStream fileStream = new FileStream(this.stylePath, FileMode.Open, FileAccess.Read)) { this.myStyle = (Style)XamlReader.Load(fileStream); } } private void AppendItem(ItemsControl ctrl, Type type) { if (type.BaseType == null) return; TreeViewItem myTreeViewItem = new TreeViewItem(){ Header = type.FullName, Style = this.myStyle}; ctrl.Items.Add(myTreeViewItem); AppendItem(myTreeViewItem, type.BaseType); } private void Window_Loaded_1(object sender, RoutedEventArgs e) { ReLayout(); myTreeView.Background = Brushes.SeaGreen; myTreeView.HorizontalAlignment = System.Windows.HorizontalAlignment.Left; myTreeView.VerticalAlignment = System.Windows.VerticalAlignment.Top; myTreeView.Margin = new Thickness(5, 5, 0, 0); this.mainGrid.Children.Add(myTreeView); var asm = Assembly.GetAssembly(typeof(TreeViewItem)); foreach (var type in asm.ExportedTypes) { var node = new TreeViewItem() { Header = type.FullName, Style = this.myStyle }; myTreeView.Items.Add(node); AppendItem(node, type); } } private void ReLayout() { if (this.ActualHeight < 500) return; if (this.ActualWidth < 500) return; myTreeView.Height = this.ActualHeight - 50; myTreeView.Width = this.ActualWidth / 2; } private void Window_StateChanged_1(object sender, EventArgs e) { ReLayout(); } private void Window_SizeChanged_1(object sender, SizeChangedEventArgs e) { ReLayout(); } } }