一 .NET Core桌面应用
主要介绍关于桌面开发四个方面:Windows平台、.NET Core 3 平台上的WPF,Winform, 应用打包解决方案 MSIX 和 XAML 群岛访问原来UWP的控件,让我们的应用程序迅速现代化。
1 Windows平台应用开发
Windows平台上的应用开发,我们通常会选择以下三个技术:Windows Forms、Windows Presentation Foundation、Universal Windows Platform (UWP)。这些选项只是我们针对 Windows 开发应用时所拥有的不同 UI 框架选项。更重要的是, 当你优化你的应用针对Windows 10时, 你会得到更多的创新、Api 和windows 10操作系统为您提供的好处。
个UI 框架现在都是开源的:
Windows Presentation Foundation: https://github.com/dotnet/wpf
Windows Forms: https://github.com/dotnet/winforms
Windows 10 XAML: https://github.com/Microsoft/microsoft-ui-xaml
2 WPF,Winform(基于.NET Core 3 平台)
.NET Framework 4.8 已经发布,.NET 4.8 已经帮助我们解决了很多问题, WPF和Windows Forms的高DPI更好的至此,Windows 10 中最新的浏览器和媒体播放器的新控件,并支持最新的标准。.NET Core 3的主要特点是支持 Windows 桌面应用,包括 Windows 窗体和 WPF 应用。 你将能够在 .NET Core 3 上运行新的和现有的 Windows 桌面应用并体验 .NET Core 具有的所有优势。 托管在 XAML 岛中的 UWP 控件也可在面向 .NET Core 3 的 Windows 窗体和 WPF 应用中使用。
.NET Core 的性能更好,速度更快,.NET Core的并行安装的特性可以帮助你在发布应用程序中获取显而易见的方便,更好的打包方案MSIX, 开源,支持.NET Standard 2.1, 支持C# 8.0等还有很多新特性。
使用.NET Core 3 升级Windows 桌面应用开发的好处还有很多,下面简要的列几条:
现代运行时、BCL 和语言功能
更容易访问平台和设备的API
现代化 且可访问的的UI和输入
针对 DevOps 进行无缝的应用程序部署、更新和优化
开发人员更好进行敏捷创新
.NET可移植性分析器可帮助您识别代码中可移植或不可移植到. net Core 的部分, 为您提供完整的 Excel 报告。 第一步是从package.json迁移到 PackageReference。
最简单的方法是创建一个运行 “dotnet new wpf” 或 “dotnet new winforms” 的空 csproj。
您可以使用生成的 csproj 作为起点, 从旧 csproj 迁移您的 PackageReferences , 然后从那里开始。
大多数项目都应该是相当超前的。
如果您需要更多信息, 请按照博客文章中的步骤操作。它是非常完整的。https://devblogs.microsoft.com/dotnet/porting-desktop-apps-to-net-core/
3 MSIX
MSIX是一种Windows应用包格式,可以为所有Windows应用程序提供现代化打包体验。MSIX 是一种基于.msi, appx、 app-V和 ClickOnce 安装技术的组合构建的一种安全可靠的打包格式。
能够在不对计算机构成风险或引起“计算机腐烂”的情况下安装和卸载
开箱即用的自动更新
更容易分发,可以通过微软商店,企业自己的微软商店,文件共享,HTTP URL分发
4 UWP
从 Windows 10 版本 1903 开始,可以将 UWP XAML 控件直接添加到与窗口句柄 (HWND) 关联的 WPF、Windows 窗体或 C++ Win32 应用中的任何 UI 元素。 这意味着,你可以将最新的 UWP 功能(例如 Windows Ink 和支持 Fluent Design System 的控件完全集成到 Windows 以及桌面应用的其他显示表面中去。 此开发人员方案有时称为“XAML 岛”。
关于Windows开发,其中一个最大的抱怨是微软在Winforms和wpf的投入少;Windows10提供的大部分新特性都只是针对UWP构建的。虽然我们现在可以从.NET Framework 调用UWP API,但仅适用于不涉及UI的情况。为了解决这个问题,微软创建了两个新控件:WinForms XAML Host和WPF XAML Host,使开发人员可以把UWP编写的UI嵌入到现有WinForms/WPF应用程序。
二 创建
从工具箱中拖拽一个Button控件,修改显示名称并添加事件,如下图所示:
双击按钮,进入事件代码区域,简单添加一个弹出显示提示文字的对话框代码,如下图所示:
运行,程序创建完毕。
三 XAML
1 概述
XAML是微软创造的一种开发语言,即可拓展应用程序标记语言。扮演了HTML+CSS+JavaScript的角色。
2 剖析XAML代码
一个.xaml下会有一个.xaml.cs,.xaml.cs文件会有对应的分部类。XAML标签声明一个元素时对应的内存中的一个对象,最外层的标签元素就是后台代码的分部类。
在XAML中对象之间的层级关系,要么是并列要么是包含,全部体现在标签的关系上。那在后台类里,我们可以通过using引用其它名称空间,而在XAML代码里,我们通过xmlns特征来定义名称空间,格式如下:
xmlns:[可选的映射前缀]="名称空间"
。看下默认的XAML代码:
<Window x:Class="PLCSerialPortRecv.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:PLCSerialPortRecv"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
</Grid>
</Window>
可以发现我们有5行代码以xmlns开头,也就是“引用了5个默认的名称空间”。其中x:和mc:开头表示调用上面声明引用的名称空间。
x:它包含的类都是与解析XAML语言相关。x:Class="MyFirstWpfApplication.MainWindow"
表示将当前这个Window这个标签解析成C#类的类名。这也和我们开始验证的其为后台分部类一样。它是x:下的Attribute,只能用于根节点,且根节点的类型要与x:Class所指示的类型(且为分部类)一致。
补充 x名称空间下的其它Attribute:x:Name:
告诉编译器为这个标签生成对应的实例外还要为这个实例声明一个引用变量,变量名就是x:Name的值。还有将XAML标签所对应的对象的Name属性也设为x:Name的值,并注册到UI树上,方便查找。x:FieldModeifer 设置元素可访问级别。x:key 采用键值对等。
3 XAML语法
xaml文档是一个树形结构。
xaml中为对象属性赋值的语法:首先xaml代码不能编写程序的运行逻辑,当我们创建标签对象的时候对其属性进行必要的初始化才有使用意义。为对象属性赋值有两种方法
1.使用字符串进行简单赋值。即简单的Attribute=Value语法赋值,由于xaml语法限制,Value只能是字符串的值。
2.使用属性元素进行复杂赋值。属性元素指的是某个标签的一个元素对应这个标签的一个属性,即以元素的形式来表达一个实例的属性。
4 XAML对名称空间引用的语法
xmlns:[映射名]=“clr-namespace:类库中名称空间的名字;assembly=类库文件名”
5 窗体的关闭事件Closing 和Closed
当窗口关闭时,它会引发两个事件:Closing 和 Closed。
Closing 在窗口关闭之前引发,它提供一种机制,可以通过这种机制来阻止窗口关闭。 系统会向Closing 事件处理程序传递一个 CancelEventArgs e,该参数实现 Boolean Cancel 属性,将该属性设置为 true 可以阻止窗口关闭。
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
MessageBoxResult result = MessageBox.Show("确定是退出吗?", "询问", MessageBoxButton.YesNo, MessageBoxImage.Question);
//关闭窗口
if (result == MessageBoxResult.Yes)
e.Cancel = false;
//不关闭窗口
if (result == MessageBoxResult.No)
e.Cancel = true;
}
如果未处理Closing,或者处理但未取消,则窗口将关闭。 在窗口真正关闭之前,会引发 Closed,这时无法阻止窗口关闭。
四 控件
1 Grid
Grid和其他各个Panel比较起来,功能最多也最为复杂。要使用Grid,首先要向RowDefinitions和ColumnDefinitions属性中添加一定数量的RowDefinitions和 ColumnDefinitions元素,从而定义行数和列数;而放置在Grid面板中的控件元素都必须显示采用Row和Column附加属性定义其放置所在的行和列,这两个属性的值都是从0开始的索引数,如果没有显式设置任何行或列,Grid将会隐式地将控件加入在第0行第0列。
注意:尽管Grid面板被设计成不可见的,但可将Grid.ShowGridLines属性设置为True,从而更清晰的观察Grid面板,方便调试,可以更准确地控制Grid面板如何选择列宽和行高。
https://www.cnblogs.com/dotnet261010/p/6281915.html
1 ScrollViewer控件
内容超过空间,出现滚动条。
TextWrapping=“Wrap”,超出宽度,自动换行。
2 Panel分组类控件
3 groupBox分组框控件
4 TabControl选项卡控件
6 StackPanel(堆布局)
这个布局是比较简单的布局模式,在这个StackPanel容器,控件都是以一列,或者一行的方式来顺序排列。
StackPanel默认是垂直一列排列,通过设置Orientation这个属性来设置水平一行排序
水平
默认情况下,容器内的控件都是被拉伸的,和容易一样高或者一样宽
在垂直模式下,按钮都是和屏幕的宽带一样被拉伸,垂直排列,并且是居中显示。
垂直模式下HorizontalAlignment可以设置“Center,left,right,stretch”4个属性
如果设置center,那么容器的宽度会和按钮的宽度一样(按钮的宽度默认就是字符内容的长度),并且居中显示
如果设置Left,那么容器就会显示在屏幕的左侧,宽度和按钮宽度一样,如图示:
在容器内的各个按钮上也可以设置自己的水平排列方式,如果设置Left,那么按钮排列在容器左侧,如果是right,按钮牌子在容器右侧,如果是stretch这个按钮仍然是拉伸显示
<StackPanel x:Name="StackPanel1" Orientation="Vertical">
<Button x:Name="btn1" Content="Button1" HorizontalAlignment="Left"></Button>
<Button x:Name="btn2" Content="Button2" HorizontalAlignment="Center"></Button>
<Button x:Name="btn3" Content="Button3" HorizontalAlignment="Stretch"></Button>
<Button x:Name="btn4" Content="Button4" HorizontalAlignment="Right"></Button>
</StackPanel>
7 DockPanel停靠面板
DockPanel定义一个区域,在此区域中,您可以使子元素通过描点的形式排列,这些对象位于 Children 属性中。停靠面板类似于WinForm中控件的Dock属性。DockPanel会对每个子元素进行排序,并将根据指定的边进行停靠,多个停靠在同侧的元素则按顺序排序。在DockPanel中,指定停靠边的控件,会根据定义的顺序占领边角,所有控件绝不会交叠。
默认情况下,后添加的元素只能使用剩余空间,无论对DockPanel的最后一个子元素设置任何停靠值,该子元素都将始终填满剩余的空间。如果不希望最后一个元素填充剩余区域,可以将DockPanel属性LastChildFill设置为false,还必须为最后一个子元素显式指定停靠方向。
填充整个剩余空间
<Window x:Class="WpfDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DockPanel面板" Height="237" Width="525" WindowStartupLocation="CenterScreen">
<DockPanel>
<Button DockPanel.Dock="Left" Content="ButtonLeft"></Button>
<Button DockPanel.Dock="Top" Content="ButtonTop"></Button>
<Button DockPanel.Dock="Right" Content="ButtonRight"></Button>
<Button DockPanel.Dock="Bottom" Content="ButtonBottom"></Button>
<Button Content="ButtonTop"></Button>
</DockPanel>
</Window>
最后元素不填充剩余空间
<Window x:Class="WpfDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DockPanel面板" Height="237" Width="525" WindowStartupLocation="CenterScreen">
<DockPanel LastChildFill="False">
<Button DockPanel.Dock="Left" Content="ButtonLeft"></Button>
<Button DockPanel.Dock="Top" Content="ButtonTop"></Button>
<Button DockPanel.Dock="Right" Content="ButtonRight"></Button>
<Button DockPanel.Dock="Bottom" Content="ButtonBottom"></Button>
<Button DockPanel.Dock="Top" Content="最后一个Button不填充剩余空间"></Button>
</DockPanel>
</Window>
五 属性
1 窗体初始位置WindowStartupLocation
当窗口打开时,窗口在相对于桌面的 x 和 y 维度有一个位置。 可以通过分别检查 Left 和 Top 属性来确定此位置。 可以设置这些属性以更改窗口的位置。
通过将 WindowStartupLocation 属性设置为下面的 WindowStartupLocation 枚举值之一,还可以指定 Window 第一次出现时的初始位置:Manual(默认值)、CenterScreen、CenterOwner。
如果将起始位置指定为 Manual,并且未设置 Left 和 Top 属性,则 Window 将向 Windows 请求显示的位置。
2 Margin and Padding
在界面设计时,Margin 和Padding都是对边距进行限制的,其区别在于“一个主外,一个主内”。
<font size=3Margin (边缘)是约束控件与容器控件的边距,设置值分别代表左上右下,使用 Margin=“20” 同时指定四个值。
<font size=3Padding (衬垫)是约束控件内部输入边距的,只有部分控件有此属性。
3 Grid.ColumnDefinitions和Grid.RowDefinitions
Grid.RowDefinitions属性将Grid控件分行,属性值为RowDefinition标签,每一个RowDefinition标签将该Grid对象分为一行;
Grid.ColumnDefinitions属性将Grid控件分列,属性值为ColumnDefinition标签,每一个ColumnDefinition标签将该Grid对象分为一列;
在给每个方块添加空间时只需指定该控件的Grid.Column和Grid.Row附加属性值,前提是该控件要定义在Grid空间中,否则将找不到这两个属性,也就无法将该控件添加到指定方格中。
当指定的行或列的值大于Grid的单元格数量时,系统默认为最后一个,比如:
<Grid x:Name="LayoutRoot" Background="Blue">
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Button Grid.Column="0" Grid.Row="0" Content=" 0 , 0"></Button>
<Button Grid.Column="1" Grid.Row="1" Content=" 1 , 1"></Button>
<Button Grid.Column="2" Grid.Row="2" Content=" 2 , 2"></Button>
</Grid>
在该示例中,我们将Grid控件分为3行2列,而添加Button时我们却设定其位置分别为(0,0),(1,1),(2,2)。很明显,该Grid并不包含(2,2)–因为它只有2列,但是调试运行时系统并不会报错,而是出现下面的结果:
六 将 WPF 应用迁移到 .NET Core
官方文档:https://docs.microsoft.com/zh-cn/dotnet/desktop-wpf/migration/convert-project-from-net-framework