项目创建 一、 项目创建 1. 数据库设置 1. 数据库连接 3. 构造供货商Provider 二、 登录窗口 三、 系统设计
一、 项目创建
项目使用软件Visual Studio 2022,并安装MvvmLight 项目使用数据库SQL Server2012下载和安装过程参考自https://www.32r.com/soft/4057.html,安装后管理员账号为sa,密码为自定义密码。
1. 数据库设置
建立ShoppingDB数据库,采用默认设置,建立Member表,字段为Id(主键int)、Name(nvarchar50)、Password(nvarchar50)、Level(nvarchar50)、InsertDate(datetime) Id字段设置为是标识 ,标识增量为1 数据库建立其他表与表结构如下
1. 数据库连接
在VS界面建立Entity(截图为DAL)文件夹,并添加ADO.NET实体,命名为ShoppingModel 选择来自数据库的EF设计器 新建连接,MicroSoft SQL Server。有可能提示缺少文件,点击下一步确定安装。 服务器名称检索不到的话可以直接输入. ,代表本地服务器。数据库名称可检索到刚建立的ShoppingDB 勾选是 勾选表,点击完成
3. 构造供货商Provider
c#创建接口IProvider 设置接口IProvider为泛型,限制泛型为class 建立数据库的增删改查函数 Entity增加ProvideBase类,设置为abstract类 Entity增加MemberProvide类,继承自ProviderBase与IProvider,IProvider泛型为Member,实现接口
在ProviderBase类中定义字段 public ShoppingDBEntities db = new ShoppingDBEntities(); 修改MemberProvider类,建立增删改查代码如下
using System ;
using System. Collections. Generic ;
using System. Linq ;
using System. Text ;
using System. Threading. Tasks ; namespace 超市管理系统. Entity
{ public class MemberProvider : ProviderBase , Iprovider< Member> { public int Delete ( Member entity) { db. Entry ( entity) . State = System. Data. Entity. EntityState. Deleted; return db. SaveChanges ( ) ; } public List< Member> GetAll ( ) { return db. Member. ToList ( ) ; } public int Insert ( Member entity) { db. Entry ( entity) . State = System. Data. Entity. EntityState. Added; return db. SaveChanges ( ) ; } public int Update ( Member entity) { db. Entry ( entity) . State = System. Data. Entity. EntityState. Modified; return db. SaveChanges ( ) ; } }
}
Entity增加ProductProvider类,继承自ProviderBase与IProvider,IProvider泛型为Product 修改MemberProvider类,建立增删改查代码如下
using System ;
using System. Collections. Generic ;
using System. Linq ;
using System. Text ;
using System. Threading. Tasks ; namespace 超市管理系统. Entity
{ public class ProductProvider : ProviderBase , Iprovider< Product> { ProductProviderpublic int Delete ( Product entity) { db. Entry ( entity) . State = System. Data. Entity. EntityState. Deleted; return db. SaveChanges ( ) ; } public List< Product > GetAll ( ) { return db. Product. ToList ( ) ; } public int Insert ( Product entity) { db. Entry ( entity) . State = System. Data. Entity. EntityState. Added; return db. SaveChanges ( ) ; } public int Update ( Product entity) { db. Entry ( entity) . State = System. Data. Entity. EntityState. Modified; return db. SaveChanges ( ) ; } }
}
数据库其他表继承自ProviderBase与IProvider建立*****Provider对应的类,并增加增删改查代码。
二、 登录窗口
1. 窗口设置
数据库内Member表,点击编辑前200行 可在界面增加内容,此处增加1,admin,123,9,null VS界面创建View文件夹,创建LoginView窗体,在ViewModel文件夹内创建LoginViewModel类,并继承ViewModelBase,ViewModelBase已实现消息通知 改造 ViewModelLocator类,在原内容基础上仿照MainViewModel的写法增加以下
public class ViewModelLocator
{ public ViewModelLocator ( ) { SimpleIoc. Default. Register < LoginViewModel> ( ) ; } public LoginViewModel LoginViewModel{ get { return ServiceLocator. Current. GetInstance < LoginViewModel> ( ) ; } }
}
LoginView.xaml内增加数据上下文来源 DataContext=“{Binding Source={StaticResource Locator}, Path=LoginViewModel}” 在app.xaml中修改启动窗口为登录窗口 StartupUri=“View/LoginView.xaml” 在根目录下创建类AppData.cs,并继承ObservableObject ,使用懒汉Lazy模式,创造唯一实例 AppData.cs创建属性 public Member CurrentUser { get; set; } = new Member();
public class AppData : ObservableObject
{ public static AppData Instance{ get ; set ; } = new Lazy< AppData> ( ( ) => new AppData ( ) ) . Value; public Member CurrentUser { get ; set ; } = new Member ( ) ;
}
LoginViewModel.cs内创建的当前用户实体为只读属性 public AppData AppData => AppData.Instance;" 创建Member类的用户实体字段和属性
private Member member = new Member ( ) { Name = "admin" , Password= "123" } ;
public Member Member
{ get { return member; } set { member = value ; RaisePropertyChanged ( ) ; }
}
创建登录按钮和退出按钮的命令 LoginView.xaml界面的window命名loginView,按钮绑定命令使ElementName = loginView
#region commands public RelayCommand< LoginView> LoginCommand{ get { return new RelayCommand< LoginView> ( ( view) => { if ( string . IsNullOrEmpty ( member. Name) && string . IsNullOrEmpty ( member. Password) ) { return ; } var list = memberProvider. GetAll ( ) ; var model = list. FirstOrDefault ( t => t. Name == member. Name && t. Password == member. Password) ; if ( model != null ) { AppData. CurrentUser = model; } else { MessageBox. Show ( "用户名或密码错误!" ) ; new MainWindow ( ) . Show ( ) ; } } ) ; } } public RelayCommand< LoginView> ExitCommand { get { return new RelayCommand< LoginView> ( ( view) => { view. Close ( ) ; } ) ; } set ; } #endregion
< Window x: Class= " 超市管理系统.View.LoginView" x: Name= " 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:超市管理系统.View" mc: Ignorable= " d" WindowStartupLocation = " CenterScreen" DataContext = " {Binding Source={StaticResource Locator}, Path=LoginViewModel}" Title = " 系统登录" Height = " 250" Width = " 450" > < StackPanel VerticalAlignment = " Center" HorizontalAlignment = " Center" > < DockPanel> < TextBlock Text = " 用户名:" Width = " 50" VerticalAlignment = " Center" Height = " 25" /> < TextBox x: Name= " userNameTextBox" Text = " {Binding Member.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width = " 100" /> </ DockPanel> < DockPanel Margin = " 0 15 0 0" > < TextBlock Text = " 密 码:" Width = " 50" VerticalAlignment = " Center" Height = " 25" /> < TextBox x: Name= " passwordTextBox" Text = " {Binding Member.Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width = " 100" /> </ DockPanel> < StackPanel Orientation = " Horizontal" HorizontalAlignment = " Right" Margin = " 0 15 0 0" > < Button x: Name= " dengLu" Command = " {Binding LoginCommand}" CommandParameter = " {Binding ElementName=loginView}" Content = " 登录" Width = " 60" Height = " 25" /> < Button x: Name= " tuiChu" Command = " {Binding ExitCommand}" CommandParameter = " {Binding ElementName=loginView}" Content = " 退出" Width = " 60" Height = " 25" Margin = " 30 0 0 0" /> </ StackPanel> </ StackPanel>
</ Window>
由于在MvvmLight中已存在ViewModelBase,在ViewModel文件夹创建ViewModelBase2.cs ,继承ViewModelBase 因MainView需显示当前登录用户,需重新在MainViewModel内同样写 public AppData AppData => AppData.Instance;" ,因此作出修改LoginViewModel和MainViewModel重新继承自ViewModelBase2 ,将 public AppData AppData => AppData.Instance;" 放在ViewModelBase2内,LoginViewModel删去该行代码,MainViewModel也不需要再写该行代码。
2. 优化登录页面布局
使用Colors Lite 抓取素材颜色数值,作为背景色。 在AppData类内添加全局变量内容:系统名称、背景色、前景色。
public Member CurrentUser { get ; set ; } = new Member ( ) ; public string Title => "馒头超市管理系统" ; public SolidColorBrush Background => new SolidColorBrush ( Color. FromRgb ( 40 , 53 , 81 ) ) ; public SolidColorBrush Forgeround => new SolidColorBrush ( Colors. White) ;
LoginView.xaml界面的window.title、TextBlock的背景色并使用Effect、前景色都改为Bingding
< Window x: Class= " 超市管理系统.View.LoginView" x: Name= " 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:超市管理系统.View" mc: Ignorable= " d" Background = " {Binding AppData.Background}" WindowStartupLocation = " CenterScreen" ResizeMode = " NoResize" DataContext = " {Binding Source={StaticResource Locator}, Path=LoginViewModel}" Title = " 系统登录" Height = " 400" Width = " 800" > < Grid> < Grid.RowDefinitions > < RowDefinition Height = " 150" /> < RowDefinition/> </ Grid.RowDefinitions> < TextBlock Grid.Row = " 0" Text = " {Binding AppData.Title}" VerticalAlignment = " Center" HorizontalAlignment = " Center" Foreground = " White" FontSize = " 30" > < TextBlock.Effect> < DropShadowEffect/> </ TextBlock.Effect> </ TextBlock> < StackPanel Grid.Row = " 1" HorizontalAlignment = " Center" VerticalAlignment = " Top" > < DockPanel> < TextBlock Text = " 用户名:" Width = " 50" VerticalAlignment = " Center" Foreground = " {Binding AppData.Forgeround}" Height = " 25" /> < TextBox x: Name= " userNameTextBox" Text = " {Binding Member.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width = " 100" /> </ DockPanel> < DockPanel Margin = " 0 15 0 0" > < TextBlock Text = " 密 码:" Width = " 50" VerticalAlignment = " Center" Foreground = " White" Height = " 25" /> < TextBox x: Name= " passwordTextBox" Text = " {Binding Member.Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width = " 100" /> </ DockPanel> < StackPanel Orientation = " Horizontal" HorizontalAlignment = " Right" Margin = " 0 15 0 0" > < Button x: Name= " dengLu" Command = " {Binding LoginCommand}" CommandParameter = " {Binding ElementName=loginView}" Content = " 登录" Width = " 60" Height = " 25" /> < Button x: Name= " tuiChu" Command = " {Binding ExitCommand}" CommandParameter = " {Binding ElementName=loginView}" Content = " 退出" Width = " 60" Height = " 25" Margin = " 30 0 0 0" /> </ StackPanel> </ StackPanel> </ Grid>
</ Window>
三、 系统设计
1.菜单设计
主界面采用两行布置,第二行为底部状态栏,绑定AppDate.Current.Name 显示当前用户的登录名称 主显示区分三列,第一列为菜单栏,第二列分竖线,第三列为用户控件区域 网络下载开源字体库 https://fontawesome.com.cn/,http://doc.vrd.net.cn/fontawesome/cheatsheet/,使用方式展示在下面代码中。 sln添加Style文件夹,新建RadioButtons.xaml,左侧一级菜单采用RadioButton设计,在RadioButtons.xaml设置Style,分别设计了Content和Tag的Style 设置触发器,鼠标移入背景色发生变化,代码如下:
< ResourceDictionary xmlns = " http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns: x= " http://schemas.microsoft.com/winfx/2006/xaml" > < Style x: Key= " MenuRadioButtonStyle" TargetType = " RadioButton" > <Setter Property="Foreground" Value="#eeefff" /><Setter Property="FontSize" Value="16" /><Setter Property="Template" ><Setter.Value><ControlTemplate TargetType="RadioButton" ><!--此时已将radio的模板形状设置为了border,将border的背景色绑定radiobutton背景色,触发器才会生效--><Border Background=" { TemplateBinding Background} "><Grid><Grid.ColumnDefinitions><ColumnDefinition Width="30" /><ColumnDefinition Width="auto" /></Grid.ColumnDefinitions><TextBlock Grid.Column="0" Text=" { TemplateBinding Tag} " FontFamily=" /Fonts/#FontAwesome" Margin=" 5"/><TextBlock Grid.Column="1" Text=" { TemplateBinding Content} " Margin=" 5"/></Grid></Border><ControlTemplate.Triggers><!--触发器的目标是radiobutton的背景色--><Trigger Property="IsMouseOver" Value="True" ><Setter Property="Background" Value="red" /></Trigger><Trigger Property="IsMouseOver" Value="False" ><!--透明色--><Setter Property="Background" Value="Transparent" /></Trigger><Trigger Property="IsChecked" Value="True" ><Setter Property="Background" Value="Goldenrod" /></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter> </ Style>
</ ResourceDictionary>
< Window x: Class= " 超市管理系统.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:超市管理系统" xmlns: view= " clr-namespace:超市管理系统.View" mc: Ignorable= " d" Title = " 馒头超市管理系统" Height = " 800" Width = " 1200" Background = " {Binding AppData.Background}" DataContext = " {Binding Source={StaticResource Locator}, Path=Main}" > < Grid> < Grid.RowDefinitions> < RowDefinition/> < RowDefinition Height = " auto" /> </ Grid.RowDefinitions> < Grid Grid.Row = " 0" > < Grid.ColumnDefinitions> < ColumnDefinition Width = " 150" /> < ColumnDefinition Width = " 1" /> < ColumnDefinition Width = " *" /> </ Grid.ColumnDefinitions> < Grid Grid.Column = " 0" > < Grid.RowDefinitions> < RowDefinition Height = " auto" /> < RowDefinition/> </ Grid.RowDefinitions> < StackPanel Orientation = " Horizontal" Grid.Row = " 0" > < TextBlock Text = "  " FontFamily = " /Fonts/#FontAwesome" Margin = " 10" FontSize = " 30" > < TextBlock.Foreground> < LinearGradientBrush> < GradientStop Offset = " 0" Color = " #C2F486" /> < GradientStop Offset = " 1" Color = " Red" /> </ LinearGradientBrush> </ TextBlock.Foreground> </ TextBlock> < TextBlock Text = " {Binding AppData.Title}" Margin = " 0" Foreground = " White" FontSize = " 20" VerticalAlignment = " Center" /> </ StackPanel> < StackPanel Grid.Row = " 1" > < RadioButton x: Name= " IndexView" Style = " { StaticResource MenuRadioButtonStyle} " Content = " 首页" Tag = "  " Checked = " View_Checked" /> < RadioButton x: Name= " OrderView" Style = " { StaticResource MenuRadioButtonStyle} " Content = " 商品下单" Tag = "  " Checked = " View_Checked" /> < RadioButton Style = " { StaticResource MenuRadioButtonStyle} " Content = " 商品管理" Tag = "  " /> < RadioButton Style = " { StaticResource MenuRadioButtonStyle} " Content = " 顾客管理" Tag = "  " /> < RadioButton Style = " { StaticResource MenuRadioButtonStyle} " Content = " 供应商管理" Tag = "  " /> < RadioButton Style = " { StaticResource MenuRadioButtonStyle} " Content = " 出库管理" Tag = "  " /> < RadioButton Style = " { StaticResource MenuRadioButtonStyle} " Content = " 入库管理" Tag = "  " /> < RadioButton Style = " { StaticResource MenuRadioButtonStyle} " Content = " 订单详情" Tag = "  " /> < RadioButton Style = " { StaticResource MenuRadioButtonStyle} " Content = " 用户管理" Tag = "  " /> < RadioButton Style = " { StaticResource MenuRadioButtonStyle} " Content = " 系统设置" Tag = "  " /> </ StackPanel> </ Grid> < Border Grid.Column = " 1" Background = " #22304B" /> < ContentControl Grid.Column = " 2" x: Name= " container" > < view: IndexView/> </ ContentControl> </ Grid> < StatusBar Grid.Row = " 1" > < StatusBarItem> < TextBlock Text = " 当前用户:" /> </ StatusBarItem> < StatusBarItem> < TextBlock Text = " {Binding AppData.CurrentUser.Name}" /> </ StatusBarItem> </ StatusBar> </ Grid>
</ Window>
2. 功能界面切换
在View文件夹创建用户控件IndexView.xaml,ViewModel文件夹创建IndexViewModel.cs,在ViewModelLocator中按格式添加IndexViewModel 采用相同 的方法依次为每个菜单按钮完成上述操作
public class ViewModelLocator
{ public ViewModelLocator ( ) { SimpleIoc. Default. Register < IndexViewModel> ( ) ; SimpleIoc. Default. Register < OrderViewModel> ( ) ; } public IndexViewModel IndexViewModel => ServiceLocator. Current. GetInstance < IndexViewModel> ( ) ; public OrderViewModel OrderViewModel => ServiceLocator. Current. GetInstance < OrderViewModel> ( ) ;
}