193行代码构建轻量WPF MVVM
什么是 WPF Mvvm
使用WPF技术做开发,如果说不知道mvvm或不会mvvm总有一种会被鄙夷感觉,至于什么是wpf mvvm,呃,这个‘深刻’的话题,百度,必应,谷歌随便你啦。
怎么构建193行的轻量MVVM呢
在了解wpf mvvm 后,那么我们可以开始设计我们的轻量mvvm了
- NotifyPropertyBase ,实现了INotifyPropertyChanged(这是什么?呃,百必谷)接口,主要做为ViewModel和Model的基类;
- RelayCommand,实现ICommand接口,如果实在不好理解,就‘粗犷’的认为,这就是一个‘超级’事件;
如实现‘超级’事件功能:
1.RelayCommand,无参命令;
2.RelayCommand,带参命令;
3.RelayEventCommand,E->EventArgs事件命令,解决需要在View Model中获取事件参数功能;
4.RelayEventCommand<E,T>,E->EventArgs,T-Parameter事件带参命令,如果又想得到事件,又想从UI上取一个元素会来,这是一个好帮手
- CommandEventParameter,怎么把事件和参数传到View Model呢?没错就是这个家伙干的;
- IEventArgs 和 IEventParameter<E, T> ,IEventArgs< E>这家伙,负责告诉VIewModel事件相关内容;IEventParameter<E, T>看,就是多了一个T,T就是参数嘛,所以这个家伙就是负责把事件相关对象和参数告诉给ViewModel;
贴代码咯
贴代码之前,你得取找一个dll库,有了它,mvvm才完整啊,‘System.Windows.Interactivity.dll’
真的只有193行
namespace WpfSimpleMvvm.Mvvm
{
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interactivity;
//ViewModel/Model
public class NotifyPropertyBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
//Command
public class RelayCommand : ICommand
{
private readonly Action _ExecuteMethod;
private readonly Func<bool> _CanExecuteMethod;
#if Silverlight
public event EventHandler CanExecuteChanged;
#else
public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } }
#endif
public Boolean IsEnabled { get; set; }
public Boolean AutoInvokeRequerySuggested { get; set; }
internal RelayCommand() => this.IsEnabled = true;
public RelayCommand(Action executeMethod, Func<bool> canExecuteMethod = null) : this()
{
_ExecuteMethod = executeMethod ?? throw new ArgumentNullException($"参数‘{nameof(executeMethod)}’不能为null");
_CanExecuteMethod = canExecuteMethod;
}
public virtual bool CanExecute(object parameter)
{
if (IsEnabled)
{
if (_CanExecuteMethod != null)
{
return _CanExecuteMethod.Invoke();
}
}
return IsEnabled;
}
public virtual void Execute(object parameter)
{
if (CanExecute(parameter) == false) return;
this._ExecuteMethod?.Invoke();
if (this.AutoInvokeRequerySuggested) CommandManager.InvalidateRequerySuggested();
}
public static RelayCommand Create(Action executeMethod, Func<bool> canExecuteMethod = null) => new RelayCommand(executeMethod, canExecuteMethod);
public static RelayCommand Create<T>(Action<T> executeMethod, Func<T, bool> canExecuteMethod = null) => new RelayCommand<T>(executeMethod, canExecuteMethod);
public static RelayCommand CreateEvent<E>(Action<IEventParameter<E, Object>> executeMethod, Func<IEventParameter<E, Object>, bool> canExecuteMethod = null) => new RelayEventCommand<E>(executeMethod, canExecuteMethod);
public static RelayCommand CreateEvent<E, T>(Action<IEventParameter<E, T>> executeMethod, Func<IEventParameter<E, T>, bool> canExecuteMethod = null) => new RelayEventCommand<E, T>(executeMethod, canExecuteMethod);
}
internal class RelayCommand<T> : RelayCommand
{
private readonly Action<T> _ExecuteMethod;
private readonly Func<T, Boolean> _CanExecuteMethod;
public RelayCommand(Action<T> executeMethod, Func<T, bool> canExecuteMethod = null) : base()
{
_ExecuteMethod = executeMethod ?? throw new ArgumentNullException($"参数‘{nameof(executeMethod)}’不能为null");
_CanExecuteMethod = canExecuteMethod;
}
public override bool CanExecute(object parameter)
{
if (IsEnabled)
{
if (_CanExecuteMethod != null)
{
return _CanExecuteMethod.Invoke(parameter is T ? (T)parameter : default(T));
}
}
return IsEnabled;
}
public override void Execute(object parameter)
{
if (CanExecute(parameter))
{
_ExecuteMethod?.Invoke(parameter is T ? (T)parameter : default(T));
if (AutoInvokeRequerySuggested) CommandManager.InvalidateRequerySuggested();
}
}
}
internal class RelayEventCommand<E, T> : RelayCommand
{
private readonly Action<IEventParameter<E, T>> _ExecuteMethod;
private readonly Func<IEventParameter<E, T>, Boolean> _CanExecuteMethod;
public RelayEventCommand(Action<IEventParameter<E, T>> executeMethod, Func<IEventParameter<E, T>, Boolean> canExecuteMethod = null) : base()
{
this._ExecuteMethod = executeMethod;
this._CanExecuteMethod = canExecuteMethod;
}
public override bool CanExecute(object parameter)
{
if (IsEnabled)
{
if (_CanExecuteMethod != null)
{
return _CanExecuteMethod.Invoke(parameter is IEventParameter<E, T> ? parameter as IEventParameter<E, T> : ConvertParameter(parameter));
}
}
return IsEnabled;
}
public override void Execute(object parameter)
{
var _para = ConvertParameter(parameter);
if (CanExecute(_para) == false) return;
_ExecuteMethod.Invoke(_para);
if (AutoInvokeRequerySuggested) CommandManager.InvalidateRequerySuggested();
}
private IEventParameter<E, T> ConvertParameter(object parameter)
{
if (parameter is IEventParameter<object, object> _para)
{
return EventParameter.Create<E, T>(_para.Sender, _para.EventArgs, _para.Parameter);
}
throw new Exception($"参数类型不匹配,请使用实现{typeof(IEventParameter<,>)}接口的实例做为参数");
}
}
internal class RelayEventCommand<E> : RelayEventCommand<E, object>
{
public RelayEventCommand(Action<IEventParameter<E, Object>> executeMethod) : base(executeMethod, null) { }
public RelayEventCommand(Action<IEventParameter<E, Object>> executeMethod, Func<IEventParameter<E, Object>, bool> canExecuteMethod) : base(executeMethod, canExecuteMethod) { }
}
//EventToCommand
public interface IEventArgs<E>
{
object Sender { get; }
E EventArgs { get; }
}
public interface IEventParameter<E, T> : IEventArgs<E>
{
T Parameter { get; }
}
internal class EventParameter
{
private class EventParameterImp<E, T> : IEventParameter<E, T>
{
public object Sender { get; set; }
public E EventArgs { get; set; }
public T Parameter { get; set; }
}
public static IEventParameter<E, T> Create<E, T>(object sender, object args, object parameter)
{
var result = new EventParameterImp<E, T>() { Sender = sender };
if (args is E)
{
result.EventArgs = (E)args;
}
else
{
throw new Exception($"事件命令,事件参数类型转换失败。{args.GetType().FullName} 不能转换为 {typeof(E).FullName}");
}
if (parameter != null)
{
if (parameter is T)
{
result.Parameter = (T)parameter;
}
else
{
throw new Exception($"事件命令,自定义参数类型转换失败。{parameter.GetType().FullName} 不能转换为 {typeof(T).FullName}");
}
}
return result;
}
}
public class CommandEventParameter : TriggerAction<DependencyObject>
{
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(nameof(Command), typeof(RelayCommand), typeof(CommandEventParameter));
public static readonly DependencyProperty ParameterProperty = DependencyProperty.Register(nameof(Parameter), typeof(object), typeof(CommandEventParameter));
public RelayCommand Command { get => (RelayCommand)GetValue(CommandProperty); set => SetValue(CommandProperty, value); }
public object Parameter { get => GetValue(ParameterProperty); set => SetValue(ParameterProperty, value); }
protected override void Invoke(object eventArgs)
{
if (AssociatedObject != null)
{
if (Command?.GetType().Name.Contains("RelayEventCommand`") == true)
{
Command.Execute(EventParameter.Create<object, object>(AssociatedObject, eventArgs, Parameter));
}
else
{
throw new Exception($"无法使用的命令类型,命令类型不匹配,请使用‘{typeof(RelayEventCommand<,>).FullName}’类型");
}
}
}
}
}
怎么用呢,那么创建一个工程吧
工程结构
别忘了引用‘System.Windows.Interactivity.dll’
构建MVVM应用
1.MVVM-Model Person.cs 这个就是我们的Model了,也就是MVVM 中的M
2.MVVM-VIew MainWindowVIew 这个是View,就是 MVVM中V啦
既然是MVVM模式,那么MainWindowVIew.cs是可以不写任何代码的哦,所以我们只需要用MainWindowVIew.xam来构建我们的View就可了
示效果
3.MVVM-VIewModel MainWindowViewModel 这个是ViewModel,也即是MVVM中的VM
结尾
按一下F5看看效果吧