实习第五周
又开了一个会讨论需求,然后讨论来讨论去,最后发现安卓平板操作性太差不能满足需求,需要surface作为移动终端进行操作,而且这个软件(平台)的使用环境不联网,B/S架构无法发挥特性,只能使用最原始的一体的结构,从一个网站的开发变成了一个桌面应用程序的开发,数据库则使用Access。
我只能学习C#开发了,桌面展现具体技术则用WPF。
WPF全称Windows Presentation Foundation,使用XAML一种类XML语言,不同于Windows Form使用的resx文件,使用了全新的标记方法。顶级标记为Window标签,然后嵌套一个布局(大多为Grid),然后在这个布局下添加控件或者布局。
布局主要继承自FrameworkElement类,控件则主要继承自Control类(Control类继承自FrameworkElement类)主要负责行为,其中控件的展现则继承自ControlTemplate类。
控件展现的自定义需要给该控件自定义Style字段,通过的<Setter Property=”Template”>设置自定义的ControlTemplate。
获取控件默认的Style需要用到反射的方法,以下是一个查看控件默认Style的工具代码。
<Window 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" mc:Ignorable="d" x:Class="ControlTemplateBrowser.MainWindow" Title="MainWindow" Height="768" Width="1301" Loaded="Window_Loaded"> <Grid x:Name="grid"> <ListBox x:Name="lstTypes" HorizontalAlignment="Left" Height="639" Margin="35,27,0,0" VerticalAlignment="Top" Width="348" SelectionChanged="lstTypes_SelectionChanged"/> <TextBox x:Name="txtTemplate" HorizontalAlignment="Left" Height="639" Margin="439,27,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="816"/> </Grid> </Window>
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.Reflection; using System.Xml; using System.Windows.Markup; namespace ControlTemplateBrowser { /// <summary> /// MainWindow.xaml 的交互逻辑 /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void Window_Loaded(object sender, EventArgs e) { Type controlType = typeof(Control); List<Type> derivedTypes = new List<Type>(); Assembly assembly = Assembly.GetAssembly(typeof(Control)); foreach(Type type in assembly.GetTypes()) { if(type.IsSubclassOf(controlType) && !type.IsAbstract && type.IsPublic) { derivedTypes.Add(type); } } //derivedTypes.Sort(); lstTypes.ItemsSource = derivedTypes; } private void lstTypes_SelectionChanged(object sender, SelectionChangedEventArgs e) { try { Type type = (Type)lstTypes.SelectedItem; ConstructorInfo info = type.GetConstructor(Type.EmptyTypes); Control control = (Control)info.Invoke(null); control.Visibility = Visibility.Collapsed; grid.Children.Add(control); ControlTemplate tempate = control.Template; XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; StringBuilder sb = new StringBuilder(); XmlWriter writer = XmlWriter.Create(sb, settings); XamlWriter.Save(tempate, writer); txtTemplate.Text = sb.ToString(); grid.Children.Remove(control); } catch (Exception err) { txtTemplate.Text = "error" + err.Message; } } } }
当然这样的桌面应用程序使用系统默认的Theme是不行,通常需要自定义窗体的展现形式,但是在给WindowStyle设置为None后,却发现通过改变WindowState的值来实现最大化会让窗体遮盖住任务栏。
查阅了网上许多资料,发现很难用一般方法来解决这个问题。假如通过设置窗体的宽高以及位置来进行最大化的方法,会导致窗体难以还原。网上给出的一般解决思路是Hook进系统调用,传递普通SingleBorderWindow最大化的消息。
我这里没有用这个方法,用了另一种方法WindowChrome。这好像是RibbonWindow下的一个类,虽然完整路径是System.Windows.Shell.WindowChrome。
然而MSDN上写了一句
用于 XAML 的 XMLNS:未映射到 xmlns。
这根本不知道怎么用,只能引用外部的Microsoft.Windows.Shell项目,只能写成这样的形式
<Window 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:shell="clr-namespace:Microsoft.Windows.Shell;assembly=Microsoft.Windows.Shell" xmlns:System="clr-namespace:System;assembly=mscorlib" xmlns:local="clr-namespace:ICISS_beta" x:Name="window" mc:Ignorable="d" x:Class="ICISS_beta.ManagerWindow" Title="ManagerWindow" SnapsToDevicePixels="True" ResizeMode="CanResizeWithGrip" d:DesignHeight="793.776" WindowStartupLocation="CenterScreen" Width="1280" Height="768" Padding="0" MinWidth="1024" StateChanged="Window_StateChanged"> <shell:WindowChrome.WindowChrome> <shell:WindowChrome ResizeBorderThickness="2" CaptionHeight="10" CornerRadius="0,0,0,0" GlassFrameThickness="0"/> </shell:WindowChrome.WindowChrome> </Window>
9.10 update:
其实未映射的意思是已经包含了,使用方法如下
<Window.Style> <Style TargetType="{x:Type Window}"> <Setter Property="WindowChrome.WindowChrome"> <Setter.Value> <WindowChrome ResizeBorderThickness="2" CaptionHeight="12" CornerRadius="0,0,0,0" GlassFrameThickness="0"/> </Setter.Value> </Setter> </Style> </Window.Style>
这样自己用按钮实现的最大化、最小化、还原也可以像标准Window里的一样工作了。
private void Exit_Click(object sender, RoutedEventArgs e) { //if(MessageBox.Show("是否要退出","确认",MessageBoxButton.OKCancel) == MessageBoxResult.OK) { Application.Current.Shutdown(); } } private void Max_Click(object sender, RoutedEventArgs e) { this.WindowState = WindowState.Maximized; //this.Height = SystemParameters.WorkArea.Height; //this.Width = SystemParameters.WorkArea.Width; //this.Left = 0; //this.Top = 0; Max.Visibility = Visibility.Hidden; Restore.Visibility = Visibility.Visible; } private void Min_Click(object sender, RoutedEventArgs e) { //this.Hide(); this.WindowState = WindowState.Minimized; } private void Restore_Click(object sender, RoutedEventArgs e) { //this.Height = 695; //this.Width = 1024; this.WindowState = WindowState.Normal; this.WindowStartupLocation = WindowStartupLocation.CenterScreen; Restore.Visibility = Visibility.Hidden; Max.Visibility = Visibility.Visible; } private void Window_StateChanged(object sender, EventArgs e) { if (this.WindowState == WindowState.Maximized) { Max.Visibility = Visibility.Hidden; Restore.Visibility = Visibility.Visible; } if (this.WindowState == WindowState.Normal) { Restore.Visibility = Visibility.Hidden; Max.Visibility = Visibility.Visible; } }