WPF基本开发

实习第五周

又开了一个会讨论需求,然后讨论来讨论去,最后发现安卓平板操作性太差不能满足需求,需要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;
	}
}

 

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注