优势UWP即windows通用平台,用于创建可以运行在所有Windows10以上设备的应用程序.与传统exe应用比起来,UWP应用拥有更严格的权限系统,更美观的操作界面,更强大的自定义控件以及更方便的自适应布局.
界面布局与Android类似,UWP应用采用XAML作为布局文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <Page x:Class="MailSystem_UWP.View.LoginPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:MailSystem_UWP.View" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Height="475" Width="354"> <Grid Height="325" VerticalAlignment="Center" HorizontalAlignment="Center" Width="288"> <Grid.RowDefinitions> <RowDefinition Height="288*"/> <RowDefinition Height="79*"/> </Grid.RowDefinitions> <TextBlock Margin="10,70,0,0" Text="用户名" TextWrapping="Wrap" VerticalAlignment="Top" HorizontalAlignment="Left" Width="42" Height="19"/> <TextBox x:Name="text1" Margin="10,94,10,0" Text="" TextWrapping="Wrap" VerticalAlignment="Top" KeyDown="onKeyDown_1" Height="32"/> <TextBlock HorizontalAlignment="Left" Margin="10,156,0,0" Text="密码" TextWrapping="Wrap" VerticalAlignment="Top" Height="19" Width="28"/> <PasswordBox x:Name="text2" Margin="10,180,10,0" VerticalAlignment="Top" InputScope="Password" Password="" KeyDown="onKeyDown_2" Height="32"/> <Button x:Name="button_login" Content="登录" VerticalAlignment="Bottom" Click="onLoginClick" Margin="0,0,10,10" RenderTransformOrigin="0.131,-0.19" HorizontalAlignment="Right" Height="32" Width="66" Grid.Row="1"/> <TextBlock x:Name="label1" HorizontalAlignment="Left" Margin="10,131,0,0" Foreground="Red" Text="请输入用户名" TextWrapping="Wrap" VerticalAlignment="Top" Visibility="Collapsed" Height="19" Width="84"/> <TextBlock x:Name="label2" HorizontalAlignment="Left" Margin="10,217,0,0" Foreground="Red" Text="请输入密码" TextWrapping="Wrap" VerticalAlignment="Top" Visibility="Collapsed" Height="19" Width="70"/> <TextBlock HorizontalAlignment="Center" Margin="0,10,0,0" Text="登录到MailSystem" TextWrapping="Wrap" VerticalAlignment="Top" FontSize="22" Height="29" Width="177"/> <Button x:Name="button_reg" Content="注册" VerticalAlignment="Bottom" Click="onRegClick" Margin="0,0,212,10" RenderTransformOrigin="0.131,-0.19" HorizontalAlignment="Right" Height="32" Width="66" Grid.Row="1"/> </Grid> </Page>
对于初学者,可以使用拖动的方式布局,对于高级开发者,可以前往XAML 概述学习XAML语法,因为许多自定义样式,画笔,布局都是无法通过拖动实现的
异步任务与UI线程当用户点击一个按钮,系统自动生成一个消息,并插入到UI消息队列中,UI线程处理了这个消息,响应了点击事件.如果在点击事件中进行联网或文件读写等耗时操作,就会导致接下来的消息被阻塞,UI线程无法处理后面的消息,造成界面卡死.
Thread类使用Thread进行多线程编程,其命名空间为System.Threading.
1 2 3 4 5 6 7 8 9 10 11 static void Main (string [] args ){ Thread thread = new Thread(cal); thread.Start(); } public static void cal (){ Console.Write("123" ); Console.ReadLine(); }
修改thread.IsBackground属性来决定线程运行在前台还是后台,前后台的区别是:当前台线程结束,无论后台线程是否执行完成,都会被强制结束.因此后台线程适合用来监听,而不是保存数据.应用程序的主线程和new Thread()创建的线程默认都是前台线程,如果这些线程都结束,程序随即退出.
Task使用Task.Run方法在线程池上创建新的后台线程,并返回Task句柄. 命名空间: System.Threading.Tasks 例如,在后台进行登录操作
1 Task.Run(() => _Login(username, password));
异步方法使用Task可以在后台执行操作,并返回结果,但是当前线程仍然会被Task中的代码阻塞,使用async修饰的异步方法,允许方法中断,并在后台线程结束后从中断处继续执行.
1 2 3 4 5 6 7 8 9 10 11 12 private async void onLoginClick (object sender, RoutedEventArgs e ){ string username = text1.Text; string password = text2.Password; SetAvailable(false ); await Task.Run(() => _Login(username, password)); SetAvailable(true ); }
在检测登录信息前,将按钮设置为不可用状态,使用await修饰的Task语句,将检测登录信息的函数放在后台执行,并中断当前代码,当_Login方法结束时,程序从中断处继续执行,将按钮设置为可用.
使用该方法不会阻塞onLoginClick()所在的线程,因此不会造成界面卡死.
在后台更新UI为了在后台线程中更新UI,需要将代码切换至UI线程执行,使用
1 CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Priority, () => { action(); })
方法将action()插入UI消息队列中,并由UI线程执行.值得注意的是,一旦lambda表达式里的代码开始执行,该函数就会立即返回,因此不应该在lambda表达式中进行需要等待的操作,例如请求用户输入.
为了方便调用,我已经写好了Invoke()方法,你可以直接复制下面的代码
1 2 3 4 public async static void Invoke (Action action, CoreDispatcherPriority Priority = CoreDispatcherPriority.Normal ) { await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Priority, () => { action(); }); }
Invoke()方法接收一个函数,并在UI线程执行.
示例代码如下
1 2 3 4 5 6 7 8 9 10 11 Invoke(() => { MessageDialog dialog = new MessageDialog("内容" ) { Title = "标题" }; dialog.Commands.Add(new UICommand("好的" )); dialog.DefaultCommandIndex = 0 ; dialog.CancelCommandIndex = 1 ; dialog.ShowAsync(); });
页面与跳转右键解决方案-添加-新建项,选择空白页,即可新建页面.
创建JumpTo方法和OnBackClick方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public static void JumpTo (Type page ){ Frame root = Window.Current.Content as Frame; Windows.UI.Core.SystemNavigationManager.GetForCurrentView().BackRequested += OnBackClick; SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = root.CanGoBack ? AppViewBackButtonVisibility.Visible : Windows.UI.Core.AppViewBackButtonVisibility.Collapsed; root.Navigated += OnNavigated; root.Navigate(page); } private static void OnBackClick (object sender, BackRequestedEventArgs e ){ Frame rootFrame = Window.Current.Content as Frame; if (rootFrame == null ) return ; if (rootFrame.CanGoBack && e.Handled == false ) { e.Handled = true ; rootFrame.GoBack(); } }
JumpTo()方法用于跳转至指定页面,并在左上角创建返回按钮,点击返回按钮后执行OnBackClick()里的代码.之后你就可以使用
来跳转到指定页面.
画笔使用自定义画笔可以修改控件的样式,例如边框颜色.
纯色画笔纯色画笔可以指定绘制某一种颜色.先定义颜色color为绿色
1 2 3 4 5 6 7 private static Color color = new Color() { A = 255 , R = 0 , G = 255 , B = 0 };
注意Color的命名空间是Windows.UI,而不是System.Drawing.
定义纯色画笔,并使用color初始化
1 public static SolidColorBrush brush = new SolidColorBrush(color);
应用画笔
1 text1.Foreground = brush;
渐变画笔渐变画笔用于绘制包含渐变颜色的界面
定义LinearGradientBrush与GradientStop
1 2 3 LinearGradientBrush brush = new LinearGradientBrush(); GradientStop gradientStop1 = new GradientStop(); GradientStop gradientStop2 = new GradientStop();
LinearGradientBrush即为渐变画笔,以下图为例 渐变方向为(0,0)到(1,1),即起点和终点,那么向量(1,1)即是渐变向量.为了描述该向量,需要定义向量的起点与终点,并在向量上的不同地方定义不同的颜色.定义颜色需要用到GradientStop,我们称GradientStop为梯度点
现在初始化梯度点,并修改背景画笔
1 2 3 4 5 6 7 8 9 gradientStop1.Color = new Windows.UI.Color() { A = 255 , R = 255 , G = 0 , B = 0 }; gradientStop1.Offset = 0 ; gradientStop2.Color = new Windows.UI.Color() { A = 255 , R = 0 , G = 0 , B = 255 }; gradientStop2.Offset = 1 ; brush.GradientStops.Add(gradientStop1); brush.GradientStops.Add(gradientStop2); brush.StartPoint = new Point(0 , 0 ); brush.EndPoint = new Point(1 , 0 ); grid.Background = brush;
这是效果 Color是梯度点的颜色,Offset规定了梯度点在整个渐变向量中的位置,范围为0∼1.如果你输入0.5,那么画笔的前50%是渐变图案,后50%是纯色,就像下面这张图 如果你输入2,那么画笔就会有一半画到窗体外面,也就是说只有前50%的画笔有效,比如下面这张图,你看不到蓝色,因为蓝色被画到外面了 StartPoint和EndPoint分别是画笔相对于绘制区域的起点和终点坐标,即是渐变向量.x,y轴的正方向分别是向右和向下,(0,0)∼(1,1)是默认区域,这是斜向下的渐变. 为了实现垂直方向的渐变,需要定义向量(0,1),因此StartPoint为(0,0),EndPoint为(0,1) 起始点和终点也可以小于1,如果它们分别为(0,0),(0.5,0.5),这说明画笔只对整个Page的左上角有效.如下图 左下方和右上角颜色不是纯色,这是因为之前的渐变向量填充了这里的颜色,而右下角不受渐变向量的控制,因此是纯蓝色
MySQL数据库 安装MySql包在VS的下方打开“程序包管理器控制台”
如果没有则转到“视图”->“其他窗口”->“程序包管理器控制台”,第一次打开需要初始化,一般在5秒左右 使用命令
1 Install-Package MySql.Data
来安装MySQL驱动
建立连接定义连接语句
1 2 3 4 5 6 7 8 9 10 11 12 private const string DATABASE_SERVER = "localhost" ;private const string DATABASE_NAME = "dearxuan" ;private const string DATABASE_USER = "root" ;private const string DATABASE_PASSWORD = "root" ;private const string DATABASE_PORT = "3306" ;private const string SQL_CONNECTION_STR = "server=" + DATABASE_SERVER + ";user=" + DATABASE_USER + ";database=" + DATABASE_NAME + ";port=" + DATABASE_PORT + ";password=" + DATABASE_PASSWORD + ";SslMode=None" ;
定义连接,命令,结果集
1 2 3 private static MySqlConnection connection;private static MySqlCommand command;private static MySqlDataReader reader;
读取数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 connection = new MySqlConnection(SQL_CONNECTION_STR); connection.Open(); command = new MySqlCommand(“SELECT * FROM dearxuan”, connection); reader = command.ExecuteReader(); while (reader.read()){ string username = reader[0 ].ToString(); string password = reader[1 ].ToString(); }
SQL注入防御使用预编译的方法来预防SQL注入攻击.预编译语句不包含数据的值,并且会在填入值之前进行语法分析,之后填入的值即使包含了SQL关键字也仍然会被当成字符串处理
在SQL语句中以"@"开头的字符串代替原本值的位置,并使用AddWithValue()来替换值
1 2 3 4 5 string sql = "SELECT * FROM dearxuan WHERE username=@username AND password=@password" command = new MySqlCommand(sql, connection); command.Parameters.AddWithValue("username" , username); command.Parameters.AddWithValue("password" , password); reader = command.ExecuteReader();