三层架构:DAL 、BLL 、UI
UI 表示层(界面层)
BLL 业务逻辑
DAL 数据访问层
第一部分:访问数据库
第二部分:检验是否为空
第三部分:检验用户名和密码,实现登录效果
1、在“Common”文件夹,创建“LoginValidationBehavior.cs”,验证是否异常,
代码如下:
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Interactivity;
namespace StudentMgrDemo.Common
{
public class LoginValidationBehavior:Behavior<FrameworkElement>
{
/// <summary>
/// 记录异常的数量
/// </summary>
/// <remarks>在一个页面里面,所有控件的验证错误信息都会传到这个类上,每个控制需不需要显示验证错误,需要分别记录</remarks>
private Dictionary<UIElement, int> ExceptionCount;
/// <summary>
/// 缓存页面的提示装饰器
/// </summary>
private Dictionary<UIElement, LoginNotifyAdorner> AdornerDict;
protected override void OnAttached()
{
ExceptionCount = new Dictionary<UIElement, int>();
AdornerDict = new Dictionary<UIElement, LoginNotifyAdorner>();
this.AssociatedObject.AddHandler(Validation.ErrorEvent, new EventHandler<ValidationErrorEventArgs>(OnValidationError));
}
/// <summary>
/// 当验证错误信息改变时,首先调用此函数
/// </summary>
private void OnValidationError(object sender, ValidationErrorEventArgs e)
{
try
{
var handler = GetValidationExceptionHandler();//插入<c:ValidationExceptionBehavior></c:ValidationExceptionBehavior>此语句的窗口的DataContext,也就是ViewModel
var element = e.OriginalSource as UIElement;//错误信息发生改变的控件
if (handler == null || element == null)
{
return;
}
if (e.Action == ValidationErrorEventAction.Added)
{
if (ExceptionCount.ContainsKey(element))
{
ExceptionCount[element]++;
}
else
{
ExceptionCount.Add(element, 1);
}
}
else if (e.Action == ValidationErrorEventAction.Removed)
{
if (ExceptionCount.ContainsKey(element))
{
ExceptionCount[element]--;
}
else
{
ExceptionCount.Add(element, -1);
}
}
if (ExceptionCount[element] <= 0)
{
HideAdorner(element);
}
else
{
ShowAdorner(element, e.Error.ErrorContent.ToString());
}
int TotalExceptionCount = 0;
foreach (KeyValuePair<UIElement, int> kvp in ExceptionCount)
{
TotalExceptionCount += kvp.Value;
}
handler.IsValid = (TotalExceptionCount <= 0);//ViewModel里面的IsValid
}
catch (Exception ex)
{
throw ex;
}
}
/// <summary>
/// 获得行为所在窗口的DataContext
/// </summary>
private NotiticationObject GetValidationExceptionHandler()
{
if (this.AssociatedObject.DataContext is NotiticationObject)
{
var handler = this.AssociatedObject.DataContext as NotiticationObject;
return handler;
}
return null;
}
/// <summary>
/// 显示错误信息提示
/// </summary>
private void ShowAdorner(UIElement element, string errorMessage)
{
if (AdornerDict.ContainsKey(element))
{
AdornerDict[element].ChangeToolTip(errorMessage);
}
else
{
var adornerLayer = AdornerLayer.GetAdornerLayer(element);
LoginNotifyAdorner adorner = new LoginNotifyAdorner(element, errorMessage);
adornerLayer.Add(adorner);
AdornerDict.Add(element, adorner);
}
}
/// <summary>
/// 隐藏错误信息提示
/// </summary>
private void HideAdorner(UIElement element)
{
if (AdornerDict.ContainsKey(element))
{
var adornerLayer = AdornerLayer.GetAdornerLayer(element);
adornerLayer.Remove(AdornerDict[element]);
AdornerDict.Remove(element);
}
}
}
}
2、Common文件夹,新建“LoginNotifyAdorner.cs”,代码如下:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace StudentMgrDemo.Common
{
public class LoginNotifyAdorner : Adorner
{
private VisualCollection _visuals;
private Canvas _canvas;
private Image _image;
private TextBlock _toolTip;
public LoginNotifyAdorner(UIElement adornedElement, string errorMessage) : base(adornedElement)
{
_visuals = new VisualCollection(this);
_image = new Image()
{
Width = 16,
Height = 16,
Source = new BitmapImage(new Uri("/warning.png", UriKind.RelativeOrAbsolute))
};
_toolTip = new TextBlock() { Text = errorMessage };
_image.ToolTip = _toolTip;
_canvas = new Canvas();
_canvas.Children.Add(_image);
_visuals.Add(_canvas);
}
protected override int VisualChildrenCount
{
get
{
return _visuals.Count;
}
}
protected override Visual GetVisualChild(int index)
{
return _visuals[index];
}
public void ChangeToolTip(string errorMessage)
{
_toolTip.Text = errorMessage;
}
protected override Size MeasureOverride(Size constraint)
{
return base.MeasureOverride(constraint);
}
protected override Size ArrangeOverride(Size finalSize)
{
_canvas.Arrange(new Rect(finalSize));
_image.Margin = new Thickness(finalSize.Width + 3, 0, 0, 0);
return base.ArrangeOverride(finalSize);
}
}
}
3、在Common文件的“NotiticationObject.cs”添加“登录 数据验证”,代码如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
namespace StudentMgrDemo.Common
{
//INotifyPropertyChanged:实现接口
public class NotiticationObject : INotifyPropertyChanged, IDataErrorInfo
{
#region 登录 数据验证
public string this[string columnName]
{
get
{
var vc = new ValidationContext(this, null, null);
vc.MemberName = columnName;
var res = new List<ValidationResult>();
var result = Validator.TryValidateProperty(this.GetType().
GetProperty(columnName).GetValue(this, null), vc, res);
if (res.Count > 0)
{
return string.Join(Environment.NewLine, res.Select(r => r.ErrorMessage).ToArray());
}
return string.Empty;
}
}
public string Error
{
get { return ""; }
}
/// <summary>
/// 页面中是否所有控制数据验证正确
/// </summary>
public virtual bool IsValid { get; set; }
#endregion
public event PropertyChangedEventHandler PropertyChanged;
//定义一个“RaisePropertyChanged”方法,让它发起请求,需要一个string参数,让它监听属性
/// <summary>
/// 发起请求
/// </summary>
/// <param name="propertyName">属性名称:监听属性</param>
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
4、在Model文件下的Login.cs类添加
6、在LoginViewModel.cs添加代码:
/// <summary>
///登录按钮-当用户名和密码数据填写是否正确
/// </summary>
public override bool IsValid
{
get { return loginObj.IsValid; }
set
{
if(value == loginObj.IsValid)
{
return;
}
loginObj.IsValid = value;
this.RaisePropertyChanged("IsValid");
}
}
7、前端LoginView.xaml绑定:
<!--账号文本框-->
<TextBox Name="idTextBoxAccount"
Text="{Binding UserName,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged,
ValidatesOnExceptions=True,
ValidatesOnDataErrors=True,
NotifyOnValidationError=True}"
Margin="-700,0,0,0" Grid.Row="2" Grid.Column="1"
Grid.ColumnSpan="2" Height="28" Width="250" VerticalContentAlignment="Center"
Foreground="#555" Style="{DynamicResource UserNameTextBoxStyle}"></TextBox>
<!--密码文本框-->
<PasswordBox Name="idTextBoxPaass" Margin="-700,0,0,0"
common:PasswordBoxHelper.Attach="True"
common:PasswordBoxHelper.Password="{Binding Password,Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged,
ValidatesOnExceptions=True,
ValidatesOnDataErrors=True,
NotifyOnValidationError=True}"
Grid.Row="4" Grid.Column="1" Grid.ColumnSpan="2" Height="28" Width="250"
VerticalContentAlignment="Center" Style="{DynamicResource PasswordBoxStyle}"
FontSize="16" Foreground="#DDD">
</PasswordBox>
xmlns:common="clr-namespace:StudentMgrDemo.Common"
<common:LoginValidationBehavior></common:LoginValidationBehavior>
执行结果: