WPF---登录窗体实现

目录

1. 效果图

2. 项目结构

3. LoginView.xaml

4. 资源字典&资源合并

5. iconfont的使用

6. 使用SqlSugar访问mysql数据库

7. 附加属性

8. 命令&属性通知

9. 重写启动

10. MD5加密

11. 随机汉字验证码

12. LoginViewModel.cs

13. 数据表

14. 程序多开提醒


1. 效果图

 

2. 项目结构

3. LoginView.xaml

<Window x:Class="LoginManagement.View.LoginView"
        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:LoginManagement.View"
        xmlns:common="clr-namespace:LoginManagement.Common"
        mc:Ignorable="d"
        Name="window"
        Title="LoginView" Height="600" Width="360"
        FontFamily="Microsoft YaHei" FontWeight="ExtraLight" ResizeMode="NoResize"
        WindowStartupLocation="CenterScreen" WindowStyle="None" AllowsTransparency="True" Background="{x:Null}">
    <Window.Resources>
        <!--资源太多,未贴出-->
    <Window.Resources>
    <Border Margin="5" Background="White" CornerRadius="10" FocusManager.FocusedElement="{Binding ElementName=username}">
        <!--阴影效果(DropShadowEffect)
           Color :  阴影的颜色; ShadowDepth: 确定阴影离开内容的距离,0的时候是晕圈;  Opacity :   阴影的透明效果,取值0~1
           Direction : 阴影相对于内容的方向,取值0~360,0时在右侧,数值增加,逆时针转动
           BlurRadius :  模糊半径,以像素为单位的正直,标识模糊开始处到边缘的距离-->
        <Border.Effect>
            <DropShadowEffect Color="Gray" ShadowDepth="0" BlurRadius="5" Opacity="0.3" Direction="0"/>
        </Border.Effect>

        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="1.8*"/>
                <RowDefinition Height="3*"/>
                <RowDefinition Height="100"/>
            </Grid.RowDefinitions>
            <Border Background="#007DFA" CornerRadius="10,10,0,0" MouseLeftButtonDown="Border_MouseLeftButtonDown"/>
            <Button VerticalAlignment="Top" HorizontalAlignment="Right" Style="{StaticResource WindowControlButtonTemplate}"
                    Content="&#xe600;"
                    Command="{Binding CloseWindowCommand}" CommandParameter="{Binding ElementName=window}"/>
            <StackPanel VerticalAlignment="Bottom" Margin="0,0,0,20">
                <Border Width="80" Height="120" Background="White" VerticalAlignment="Center" HorizontalAlignment="Center" CornerRadius="50" Margin="0,0,0,10">
                    <Border.Effect>
                        <DropShadowEffect Color="White" ShadowDepth="0" BlurRadius="5" Opacity="0.3" Direction="0"/>
                    </Border.Effect>
                    <Border Width="90" Height="120" HorizontalAlignment="Center">
                        <Border.Background>
                            <ImageBrush ImageSource="../Assets/Images/Login.jpg"/>
                        </Border.Background>
                    </Border>
                </Border>
                <TextBlock Text="WPF--------Learning" FontSize="18" Foreground="White" HorizontalAlignment="Center"/>
            </StackPanel>
            <Grid Grid.Row="1" Margin="20,5">
                <Grid.RowDefinitions>
                    <RowDefinition />
                    <RowDefinition />
                    <RowDefinition />
                    <RowDefinition />
                    <RowDefinition  MinHeight="20" Height="Auto"/>
                </Grid.RowDefinitions>
                <TextBox Text="{Binding LoginModel.UserName, UpdateSourceTrigger=PropertyChanged}" Name="username" Height="42" FontSize="16" Foreground="#555" Style="{DynamicResource UserNameTextBoxStyle}">
                    <TextBox.InputBindings>
                        <KeyBinding Key="Enter" Command="{Binding LoginCommand}" CommandParameter="{Binding ElementName=window}"/>
                    </TextBox.InputBindings>
                </TextBox>
                <PasswordBox Grid.Row="1" Height="42" FontSize="16" Foreground="#555" Style="{DynamicResource PasswordBoxStyle}"       
                             common:PasswordHelper.Password="{Binding LoginModel.Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
                    <PasswordBox.InputBindings>
                        <KeyBinding Key="Enter" Command="{Binding LoginCommand}" CommandParameter="{Binding ElementName=window}"/>
                    </PasswordBox.InputBindings>
                </PasswordBox>
                <TextBox Grid.Row="2" Text="{Binding LoginModel.ValidationCode, UpdateSourceTrigger=PropertyChanged}" Height="42" FontSize="16" Foreground="#555" Style="{DynamicResource VlidationCodeTextBoxStyle}">
                    <TextBox.InputBindings>
                        <KeyBinding Key="Enter" Command="{Binding LoginCommand}" CommandParameter="{Binding ElementName=window}"/>
                    </TextBox.InputBindings>
                </TextBox>
                <DockPanel Grid.Row="3" >
                    <Button Height="42" Width="270" Content="登    录" Command="{Binding LoginCommand}" CommandParameter="{Binding ElementName=window}"
                        Template="{StaticResource LoginButtonTemplate}" Foreground="White" FontSize="16" IsDefault="True"/>
                    <Button Content="注 册" Width="35" Height="40" Command="{Binding RegisterCommand}" HorizontalAlignment="Right"
                        Template="{StaticResource LoginButtonTemplate}" Foreground="White" FontSize="13" />
                </DockPanel>
                <TextBlock Grid.Row="4" Text="{Binding LoginModel.ErrorMessage}" Foreground="Red"  TextWrapping="Wrap" FontSize="13" LineHeight="22" HorizontalAlignment="Center" VerticalAlignment="Center"/>
            </Grid>
            <Grid   Grid.Row="2" Margin="20,0">
                <Grid.RowDefinitions>
                    <RowDefinition Height="20"/>
                    <RowDefinition/>
                </Grid.RowDefinitions>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition/>
                        <ColumnDefinition Width="20"/>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>
                    <Border BorderBrush="#DDD" BorderThickness="0,0,0,1" VerticalAlignment="Center"/>
                    <Border Grid.Column="2" BorderBrush="#DDD" BorderThickness="0,0,0,1" VerticalAlignment="Center"/>
                    <TextBlock Grid.Column="1"  Text="OR" Foreground="#CCC" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                </Grid>
                <UniformGrid Columns="5" Grid.Row="1" >
                    <UniformGrid.Resources>
                        <Style TargetType="TextBlock">
                            <Setter Property="Foreground" Value="#DDD"/>
                            <Setter Property="FontSize" Value="40"/>
                            <Setter Property="HorizontalAlignment" Value="Center"/>
                            <Setter Property="VerticalAlignment" Value="Center"/>
                            <Setter Property="FontFamily" Value="../Assets/Fonts/#iconfont"/>
                            <Style.Triggers>
                                <Trigger Property="IsMouseOver" Value="True">
                                    <Setter Property="Foreground" Value="#007DFA"/>
                                </Trigger>
                            </Style.Triggers>
                        </Style>
                    </UniformGrid.Resources>
                    <TextBlock Text="&#xe60b;"/>
                    <Border/>
                    <TextBlock Text="&#xe621;"/>
                    <Border/>
                    <TextBlock Text="&#xe619;"/>
                </UniformGrid>
            </Grid>
        </Grid>
    </Border>
</Window>

 4. 资源字典&资源合并

新建资源字典DefaultStyle.xaml,存放统一的样式资源

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:LoginManagement.Assets.Styles">
    <Style TargetType="Button" x:Key="WindowControlButtonTemplate">
        <Setter Property="Width" Value="45"/>
        <Setter Property="Height" Value="35"/>
        <Setter Property="Foreground" Value="White"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Border Background="Transparent" Name="kilter">
                        <TextBlock Text="{Binding Content, RelativeSource={RelativeSource AncestorType=Button, Mode=FindAncestor} }"
                       HorizontalAlignment="Center" VerticalAlignment="Center" FontFamily="../Fonts/#iconfont"/>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="true">
                            <Setter TargetName="kilter" Property="Background" Value="#22FFFFFF"/>
                        </Trigger>
                        <Trigger Property="IsPressed" Value="true">
                            <Setter TargetName="kilter" Property="Background" Value="#44FFFFFF"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    
</ResourceDictionary>

UI调用资源字典,资源合并

<Window.Resources>
        <ResourceDictionary Source="../Assets/Styles/DefaultStyle.xaml">
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary>
                 <!-- 此处为自身的资源样式-->
                </ResourceDictionary>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
</Window.Resources>

5. iconfont的使用

使用如下图的字体图标,跟字体一样可修改多种属性,简洁好用

① 登录iconfont-阿里巴巴矢量图标库  

② 注册账号,搜索需要的字体图标 ,选好相应图标后,点击添加入库

③ 再从库里添加至项目中,若无项目先新建

④ 进入到我的项目,如下图,复制图标下的代码(以供项目中使用)

 ⑤ 点击下载至本地,文件解压后,将其中的文件“iconfont.ttf”复制到项目中,

⑥ 调用  其中text值设置为相应图标代码;FontFamily设置为“iconfont.ttf”的路径

<TextBlock Text="&#xe60b;" FontFamily="../Assets/Fonts/#iconfont"/>

6. 使用SqlSugar访问mysql数据库

  ① 先使用NuGet安装SqlSugar和Mysql.Data和Newtonsoft.Json

  ② App.config中配置mysql连接字符串,其中密码、数据库根据自身修改

<connectionStrings>
    <add name="db" connectionString="server=127.0.0.1;user id=root;pwd=111;database=wpf_data;pooling=true;MaximumPoolSize=10;MinimumPoolSize=3;" />
  </connectionStrings>

  ③MysqlDataAccess.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SqlSugar;
using System.Configuration;
using LoginManagement.DataAccess.DataEntity;
using LoginManagement.Common;

namespace LoginManagement.DataAccess
{
    class MysqlDataAccess
    {
        public SqlSugarClient MysqlAccess { get; set; }
        private static MysqlDataAccess instance;
        
        public static MysqlDataAccess Instance
        {
            get
            {
                return instance?? (instance=new MysqlDataAccess(ConfigurationManager.ConnectionStrings["db"].ConnectionString,DbType.MySql));
            }
        }

        private MysqlDataAccess(string connStr, DbType dbType)
        {
            MysqlAccess = new SqlSugarClient(new ConnectionConfig
            {
                ConnectionString = connStr,
                DbType = dbType,
                IsAutoCloseConnection = false
            });
        }

        public SqlSugarClient GetNewdb()
        {
            string connStr = ConfigurationManager.ConnectionStrings["db"].ConnectionString;
            SqlSugarClient newdb = new SqlSugarClient(new ConnectionConfig
            {
                ConnectionString = connStr,
                DbType=DbType.MySql,
                IsAutoCloseConnection=true
            });
            return newdb;
        }

        public bool CheckUserInfo(string userName,string pwd)
        {
            var isExist = MysqlAccess.Queryable<Users>().Any(it => it.User_name == userName && it.Password == Md5Provider.GetMd5String($"{userName}@{pwd}"));
            return isExist;
        }

        public bool CheckUserValidation(string userName)
        {
            var info = MysqlAccess.Queryable<Users>().First(it => it.User_name == userName);
            if (info.Is_validation==1) return true;
            return false;
        }

        public bool CheckUserExist(string userName)
        {
            var isExist = MysqlAccess.Queryable<Users>().Any(it => it.User_name == userName);
            if (isExist) return true;
            return false;
        }

        public bool AddUser(string userName, string pwd)
        {
            Users newUser = new Users
            {
                User_name = userName,
                //MD5密码加密,  MD5对“用户名+@+密码”加密作为密码  
                Password = Md5Provider.GetMd5String($"{userName}@{pwd}"),  
                Is_validation=1,
            };
            var rtn= MysqlAccess.Insertable(newUser).AS("users").ExecuteCommand();
            if (rtn == 1) return true;
            return false;

        }
    }
}

 7. 附加属性 PasswordHelper.cs

    通过使用附加属性做为桥梁,对PasswordBox.Password属性进行更新

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;

namespace LoginManagement.Common
{
    public class PasswordHelper
    {
        static bool _isUpdating = false;
        public static readonly DependencyProperty PasswordProperty =
            DependencyProperty.RegisterAttached("Password",typeof(string),typeof(PasswordHelper),
                new FrameworkPropertyMetadata("",new PropertyChangedCallback(OnPropertyChanged)));

        public static string GetPassword(DependencyObject d)
        {
            return d.GetValue(PasswordProperty).ToString();
        }

        public static void SetPassword(DependencyObject d,string value)
        {
            d.SetValue(PasswordProperty,value);
        }

        private static void OnPropertyChanged(DependencyObject d,DependencyPropertyChangedEventArgs e)
        {
           PasswordBox passwordBox = d as PasswordBox;
            passwordBox.PasswordChanged -= PasswordBox_PasswordChanged;
            if (!_isUpdating)
                passwordBox.Password = e.NewValue?.ToString();
            passwordBox.PasswordChanged += PasswordBox_PasswordChanged;
        }

        private static void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
        {
            PasswordBox passwordBox = sender as PasswordBox;
            _isUpdating = true;
            SetPassword(passwordBox, passwordBox.Password);
            _isUpdating = false;
        }
    }
}

调用

<PasswordBox   common:PasswordHelper.Password="{Binding LoginModel.Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">                   
</PasswordBox>

8. 命令&属性通知

  命令: CommandBase.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace LoginManagement.Common
{
    public class CommandBase : ICommand
    {
        public event EventHandler CanExecuteChanged;

        public bool CanExecute(object parameter)
        {
            return DoCanExecute?.Invoke(parameter)==true;
        }

        public void Execute(object parameter)
        {
            DoExecute?.Invoke(parameter);
        }

        public Action<object> DoExecute { get; set; }
        public Func<object, bool> DoCanExecute { get; set; }
    }
}

调用

class LoginViewModel
    {
        public CommandBase CloseWindowCommand { get; set; } 
        public CommandBase LoginCommand { get; set; }

        public LoginViewModel()
        {
            InitialCommand();

        }

        private void InitialCommand()
        {
            CloseWindowCommand = new CommandBase
            {
                DoExecute = new Action<object>((o) =>
                {
                    (o as Window).Close();
                }),
                DoCanExecute = new Func<object, bool>((o) => { return true; })
            };

            LoginCommand = new CommandBase
            {
                DoExecute = new Action<object>(DoLogin),
                DoCanExecute = new Func<object, bool>((o) => { return true; })
            };

        }
}

属性修改通知: NotifyBase.cs

public class NotifyBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        //[CallerMemberName] 可以自动获取属性名称,可以不用传递属性名做参数
        public void DoNotify([CallerMemberName] string propName="")
        {
            PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(propName));
        }
    }

调用:

public class LoginModel:NotifyBase
    {
        private string _userName;

        public string UserName
        {
            get { return _userName; }
            set
            {
                _userName = value;
                DoNotify();
            }
        }
    }

9. 重写启动

App.xaml.cs  先启动LoginView,登录成功后,设置其DialogResult值为true,再启动MainView

public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
            if (new LoginView().ShowDialog()==true)
            {
                new MainView().ShowDialog();
            }
            Application.Current.Shutdown();
        }
    }

App.xaml    

<Application x:Class="LoginManagement.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:LoginManagement"
             ShutdownMode="OnExplicitShutdown">
    <Application.Resources>
         
    </Application.Resources>
</Application>

10. MD5加密

public class Md5Provider
    {
        public static string GetMd5String(string str)
        {
            MD5 mD5 = MD5.Create();
            byte[] pws = mD5.ComputeHash(Encoding.UTF8.GetBytes(str));
            string pwd = "";
            foreach (var item in pws)
            {
                pwd += item.ToString("X2");
            }
            return pwd;
        }
    }

11. 随机汉字验证码

//随机生成常用的汉字
        private string GenerateChineseWords()
        {
            string chineseWords = "";
            Random rm = new Random();
            Encoding gb = Encoding.GetEncoding("gb2312");

            for (int i = 0; i < 4; i++)
            {
                // 获取区码(常用汉字的区码范围为16-55)   
                int regionCode = rm.Next(16, 55);
                // 获取位码(位码范围为1-94 由于55区的90,91,92,93,94为空,故将其排除)   
                int positionCode;
                if (regionCode == 55)
                {
                    // 55区排除90,91,92,93,94   
                    positionCode = rm.Next(1, 90);
                }
                else
                {
                    positionCode = rm.Next(1, 95);
                }

                // 转换区位码为机内码   
                int regionCode_Machine = regionCode + 160;// 160即为十六进制的20H+80H=A0H   
                int positionCode_Machine = positionCode + 160;// 160即为十六进制的20H+80H=A0H   

                // 转换为汉字   
                byte[] bytes = new byte[] { (byte)regionCode_Machine, (byte)positionCode_Machine };
                chineseWords += gb.GetString(bytes);
            }

            return chineseWords;
        }

12. LoginViewModel.cs

   登录\注册处理

class LoginViewModel
    {
        public LoginModel LoginModel { get; set; } = new LoginModel();

        public CommandBase CloseWindowCommand { get; set; } 
        public CommandBase LoginCommand { get; set; }
        public CommandBase ChangeValidationCodeCommand { get; set; }
        public CommandBase RegisterCommand { get; set; }

        public LoginViewModel()
        {
            InitialCommand();

            LoginModel.OriginalValidationCode = GenerateChineseWords();

        }

        private void InitialCommand()
        {
            CloseWindowCommand = new CommandBase
            {
                DoExecute = new Action<object>((o) =>
                {
                    (o as Window).Close();
                }),
                DoCanExecute = new Func<object, bool>((o) => { return true; })
            };

            LoginCommand = new CommandBase
            {
                DoExecute = new Action<object>(DoLogin),
                DoCanExecute = new Func<object, bool>((o) => { return true; })
            };

            ChangeValidationCodeCommand = new CommandBase
            {
                DoExecute = new Action<object>((o) => { LoginModel.OriginalValidationCode = GenerateChineseWords(); }),
                DoCanExecute = new Func<object, bool>((o) => { return true; })
            };

            RegisterCommand = new CommandBase
            {
                DoExecute=new Action<object>(DoRegister),
                DoCanExecute=new Func<object, bool>((o)=> { return true; })
            };
        }
        
        private void DoLogin(object o)
        {
            if (string.IsNullOrEmpty(LoginModel.UserName))
            {
                LoginModel.ErrorMessage = "用户名不能为空";
                return;
            }

            if (string.IsNullOrEmpty(LoginModel.Password))
            {
                LoginModel.ErrorMessage = "密码不能为空";
                return;
            }

            if (string.IsNullOrEmpty(LoginModel.ValidationCode))
            {
                LoginModel.ErrorMessage = "验证码不能为空";
                return;
            }
            if (LoginModel.ValidationCode!= LoginModel.OriginalValidationCode)
            {
                LoginModel.ErrorMessage = "验证码错误";
                return;
            }
            LoginModel.ErrorMessage = "";
            Task.Run(new Action(()=> 
            {
                try
                {
                    bool isExist = MysqlDataAccess.Instance.CheckUserInfo(LoginModel.UserName, LoginModel.Password);
                    if (!isExist)
                    {
                        LoginModel.ErrorMessage = "用户名或者密码错误";
                        return;
                    }
                    bool is_validation = MysqlDataAccess.Instance.CheckUserValidation(LoginModel.UserName);
                    if (!is_validation)
                    {
                        LoginModel.ErrorMessage = "用户名已失效";
                        return;
                    }

                    Application.Current.Dispatcher.Invoke(new Action(()=> 
                    {
                        (o as Window).DialogResult = true;
                    })); 
                    
                }
                catch (Exception ex)
                {
                    LoginModel.ErrorMessage = ex.Message;
                }
            }));
            
        }

        private void DoRegister(object o)
        {
            if (string.IsNullOrEmpty(LoginModel.UserName))
            {
                LoginModel.ErrorMessage = "注册时,用户名不能为空";
                return;
            }

            if (string.IsNullOrEmpty(LoginModel.Password))
            {
                LoginModel.ErrorMessage = "注册时,密码不能为空";
                return;
            }

            Task.Run(new Action(()=> 
            {
                try
                {
                    var isExist = MysqlDataAccess.Instance.CheckUserExist(LoginModel.UserName);
                    if (isExist)
                    {
                        LoginModel.ErrorMessage = "用户名已被注册";
                        return;
                    }
                    var rtn= MysqlDataAccess.Instance.AddUser(LoginModel.UserName,LoginModel.Password);
                    if (rtn)
                    {
                        LoginModel.ErrorMessage = "注册成功";
                        return;
                    }
                    LoginModel.ErrorMessage = "注册异常,请重试";
                }
                catch (Exception ex)
                {
                    LoginModel.ErrorMessage = ex.Message;
                    return;
                }
                
                    
            }));


        }

    }

13. 数据表

 14. 程序多开提醒

        修改App.xaml.cs,在程序执行时进行进程判断,对是否已有程序执行做相应选项处理

public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
            if (EnsureInstance())
            {
                return;
            }
            if (new LoginView().ShowDialog()==true)
            {
                new MainView().ShowDialog();
            }
            Application.Current.Shutdown();
        }

        /// 该函数设置由不同线程产生的窗口的显示状态
        /// </summary>
        /// <param name="hWnd">窗口句柄</param>
        /// <param name="cmdShow">指定窗口如何显示。查看允许值列表,请查阅ShowWlndow函数的说明部分</param>
        /// <returns>如果函数原来可见,返回值为非零;如果函数原来被隐藏,返回值为零</returns>
        [DllImport("User32.dll")]
        private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);
        /// <summary>
        ///  该函数将创建指定窗口的线程设置到前台,并且激活该窗口。键盘输入转向该窗口,并为用户改各种可视的记号。
        ///  系统给创建前台窗口的线程分配的权限稍高于其他线程。 
        /// </summary>
        /// <param name="hWnd">将被激活并被调入前台的窗口句柄</param>
        /// <returns>如果窗口设入了前台,返回值为非零;如果窗口未被设入前台,返回值为零</returns>
        [DllImport("User32.dll")]
        private static extern bool SetForegroundWindow(IntPtr hWnd);
        private const int SW_SHOWNOMAL = 1;
        private static void HandleRunningInstance(Process instance)
        {
            ShowWindowAsync(instance.MainWindowHandle, SW_SHOWNOMAL);//显示
            SetForegroundWindow(instance.MainWindowHandle);//当到最前端
        }
        private static Process[] RuningInstance()
        {
            Process currentProcess = Process.GetCurrentProcess();
            Process[] processes = Process.GetProcessesByName(currentProcess.ProcessName);
            return processes.Where(x => x.Id != currentProcess.Id).ToArray();
        }
        private static bool EnsureInstance()
        {
            var intance = RuningInstance();
            var select = false;
            if (intance != null && intance.Count() > 0)
            {
                var result = MessageBox.Show(string.Format(CultureInfo.CurrentCulture,
                       $"软件已经在后台运行{intance.Count()}个实例!\r\n" +
                       $"路径:\r\n{GetProcessPath(intance)}\r\n\n" +
                       "请选择:\n" +
                       "1.关闭后台程序重新运行\t[是]\n" +
                       "2.显示后台程序\t\t[否]\n" +
                       "3.保留后台程序并启动新程序\t[取消]\n"),
                    "LoginManagement", MessageBoxButton.YesNoCancel, MessageBoxImage.Warning);
                switch (result)
                {
                    case MessageBoxResult.Yes:
                        KillProcess(intance);
                        break;
                    case MessageBoxResult.No:
                    case MessageBoxResult.None:
                        Array.ForEach(intance, x => HandleRunningInstance(x));
                        select = true;
                        break;
                    case MessageBoxResult.Cancel:
                        break;
                    default:
                        break;
                }
            }
            return select;
        }
        private static string GetProcessPath(Process[] processes)
        {
            var sb = new StringBuilder();
            for (int i = 0; i < processes.Count(); i++)
            {
                sb.Append($"{i + 1}:{processes[i].MainModule.FileName}\n");
            }
            return sb.ToString();
        }
        private static void KillProcess(Process[] processes)
        {
            foreach (var p in processes)
            {
                p.Kill();
                if (!p.HasExited)
                {
                    MessageBox.Show(string.Format(CultureInfo.CurrentCulture, "进程关闭失败!请手动确认进程已关闭"),
                    "LoginManagement", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
        }
    }

        效果:二次打开exe时,报以下处理提醒

异常:

1. Navicat连接Mysql-8.0.25报“2059”错误,

原因:新版本的MySQL使用的是caching_sha2_password验证方式,但此时的navicat还没有支持这种验证方式。
解决方法:将验证方式改为以前版本(5.7及以下)使用的验证方式mysql_native_password。
执行命令:

ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '密码';

'root'可以改为你自己定义的用户名,'localhost'指的是该用户开放的IP,可以是'localhost'(仅本机访问,相当于127.0.0.1),可以是具体的'...'(具体某一IP),也可以时'%'(所有IP均可问)。'密码'是你想使用的验证密码。

github地址:https://github.com/KilterW/ManagementSystem.git

参考:  朝夕教育 :WPF 客户端管理系统 (qq.com)

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值