前言
我想, 有一部分程序员应该是在二三线城市的, 虽然不知道占比, 但想来应该不在少数.
我是这部分人群中的一份子.
我们这群人, 面对的客户, 大多是国内中小企业, 或者政府的小部门. 这类客户的特点是, 资金有限, 人力有限.
什么意思呢? 就是你如果敢给他安一台 Linux 服务器, 客户的信息员和测试员会把你堵在墙角问候你全家安好, 他们 Window 都用不明白呢, 你给安 Linux, 要疯啊.
所以, Core 对我们而言, 没有意义, 因为大家都是 Windows.
关于业务
在二三线城市的我们, 立身之本不是写算法, 也不是各种高级的, 新出的技术, 而是, 写业务模块.
不要小看写业务模块, 在二三线城市, 一个不会写业务模块的程序员, 即便知识面再广, 也是个烂程序员. 为什么? 因为他不能干活呀.
其实把业务模块写好, 并不是件容易的事. 因为它涉及到对业务的理解, 对社会的认知.
以我多年的经验, 能写好业务模块的优秀开发人员, 通常都需要三四年经验. 普通一点, 大约就需要五到十年. 当然还有十年以上经验, 还很没掌握写业务的.
这里面有个特例, 那就是硕士和博士. 因为他们的年龄较大, 阅历较多, 所以, 通常两年就能把业务写的很好. 此外就没有特例了, 什么一年经验就能架构, 刚毕业就是高级程序员的, 那都是培训机构骗毕业生的.
但是, 不得不说, 高学历真的管用, 硕士博士的成材率真的很高. 大多数都能成为及格的程序员.
关于框架
回到写框架这件事. 在我看来, 写框架这件事是个程序员都能干. 但写的好坏就另说了, 所以写框架这件事还是与经验挂钩的.
在我的认知中, 技术视野相对更高, 技术范围更广的人写的框架会更好. 所以, 我认为,[实战]架构师和高级程序员, 在本质上没有区别, 都是程序员.
只是架构师技术更会好一点, 并且接受过项目的洗礼. 然而, 一个项目只能洗礼一个人, 所以能不能成为架构师, 就不能只看技术了, 要看老板给谁机会了. 说白了, 就是老板肯不肯花钱赌你能成事.
所以, 当技术相差无几, 沟通能力, 文档能力, 甚至生活状态, 家境, 毅力都是领导考察的依据. 因此, 机会不是留给有准备的人, 而是留给各方面都更出色的人.
当然, 如果老板认可你, 一年经验做架构师也不是没可能. 但在资金有限, 人员有限的二三线城市, 能遇到这样脑残的领导或老板的概率不高.
虽然架构师不是人人都能做, 但框架是可以先学会编写的, 毕竟这是个基础. 有了基础, 就算不能年轻有为, 但起码有个机会.
也许, 人家 28 岁拿到的机会, 你在 40 岁也可以拿到, 不是吗. 有机会总比没有强, 不是吗.
框架的前期准备
关于框架编写, 我不想在 Github 上放一个源码, 然后再写一篇介绍文档. 我觉得, 这种方式是高手之间的交流.
很多新手, 会被这种海量的代码压垮, 因为他们还不习惯阅读框架, 会出现开始时事倍功半, 到最后郁闷放弃的情况.
所以, 我们一起从头开始, 一起开始 MVVM 的 WPF 框架之旅吧.
框架的前期准备
框架是要一步一步编写的, 首先, 我们先定义框架包含的基本元素. 基本元素如下:
WPFUI: 就是 WPF 的 Xaml 页面.
ViewModel: 每个 WPF 页面有唯一的 ViewModel, 用来处理页面业务逻辑.
Utility: 存放一些常规处理类.
DTO: 存放数据传输用的实体类.
Proxy: 获取数据用的代理类.
先定义这五个元素, 如果后期需要, 我们再进行补充. 定义了元素后, 我们创建对应的应用程序集. 项目结构如下:
做好了项目结构后, 我们让 ViewModel 引用 DTO,Proxy,Utility 三个程序集, 然后在让 KibaFramework 引用 ViewModel, 这样就实现了上图的结构逻辑.
然后, 我们再让 ViewModel 引用 PresentationCore,PresentationFramework,System.Windows,WindowsBase,Systm.Xaml 这个五个 DLL, 它们是 WPF 的核心类库, 为了后期反射前台控件用.
我怎么知道要引用这五个类库的?
这是经验, 仅仅是经验, 没有其他.
项目约定
创建完基础结构后, 我们要做的是项目约定.(任何框架都有约定, 而且约定要高于配置, 这是约定优先原则.)
我们建立约定如下:
WPF 项目窗体以 Window 作为前缀名创建, 如 WindowMain,WindowLogin.
WPF 项目页面以 Page 作为前缀名创建, 如 PageMain,PageXXX.
WPF 项目控件 (UserControl) 以 UC 作为前缀名创建, 如 UCTable,UCXXX.
WPF 的窗体, 页面, 控件有且只有一个 ViewModel.
ViewModel 以 VM_作为前缀名 + 对应的窗体名创建, 如 VM_WindowMain,VM_PageMain.
框架的实现
做完准备工作后, 我们开始编写框架, 先从系统的核心 ViewModel 开始, 第一步, 建立 WPF 页面与 View 的关系.
首先我们创建 VM 的基类 BaseViewModel-- 之后再建立的 VM 都要引用这个基类.
在 VM 基类里, 我们通过反射实现创建 Xaml 页面, 并实现该页面的相关事件. 代码如下:
- namespace ViewModel
- {
- public class BaseViewModel : INotifyPropertyChanged
- {
- public event PropertyChangedEventHandler PropertyChanged;
- public const string UINameSapce = "KibaFramework";
- public string UIElementName = "";
- public FrameworkElement UIElement { get; set; }
- public Window WindowMain { get; set; } // 主窗体
- public EventHandler CloseCallBack = null; // 窗体 / 页面 / 控件 关闭委托
- public BaseViewModel()
- {
- WindowMain = Application.Current.MainWindow;
- SetUIElement();
- }
- #region 通过反射创建对应的 UI 元素
- public void SetUIElement()
- {
- Type childType = this.GetType();// 获取子类的类型
- string name = this.GetType().Name;
- UIElementName = name.Replace("VM_", "");
- UIElementName = UIElementName.Replace("`1", "");// 应对泛型实体
- if (name.Contains("Window"))
- {
- UIElement = GetElement<Window>();
- (UIElement as Window).Closing += (s, e) =>
- {
- if (CloseCallBack != null)
- {
- CloseCallBack(s, e);
- }
- };
- }
- else if (name.Contains("Page"))
- {
- UIElement = GetElement<Page>();
- (UIElement as Page).Unloaded += (s, e) =>
- {
- if (CloseCallBack != null)
- {
- CloseCallBack(s, e);
- }
- };
- }
- else if (name.Contains("UC"))
- {
- UIElement = GetElement<UserControl>();
- (UIElement as UserControl).Unloaded += (s, e) =>
- {
- if (CloseCallBack != null)
- {
- CloseCallBack(s, e);
- }
- };
- }
- else
- {
- throw new Exception("元素名不规范");
- }
- }
- public E GetElement<E>()
- {
- Type type = GetFormType(UINameSapce + "." + UIElementName);
- E element = (E)Activator.CreateInstance(type);
- return element;
- }
- public static Type GetFormType(string fullName)
- {
- Assembly assembly = Assembly.Load(UINameSapce);
- Type type = assembly.GetType(fullName, true, false);
- return type;
- }
- #endregion
- #region 窗体操作
- public void Show()
- {
- if (UIElement is Window)
- {
- (UIElement as Window).Show();
- }
- else
- {
- throw new Exception("元素类型不正确");
- }
- }
- public void ShowDialog()
- {
- if (UIElement is Window)
- {
- (UIElement as Window).ShowDialog();
- }
- else
- {
- throw new Exception("元素类型不正确");
- }
- }
- public void Close()
- {
- if (UIElement is Window)
- {
- (UIElement as Window).Close();
- }
- else
- {
- throw new Exception("元素类型不正确");
- }
- }
- public void Hide()
- {
- if (UIElement is Window)
- {
- (UIElement as Window).Hide();
- }
- else
- {
- throw new Exception("元素类型不正确");
- }
- }
- #endregion
- #region Message
- public void MessageBox(Window owner, string msg)
- {
- DispatcherHelper.GetUIDispatcher().Invoke(new Action(() =>
- {
- if (owner != null)
- {
- System.Windows.MessageBox.Show(owner, msg, "提示信息");
- }
- else
- {
- System.Windows.MessageBox.Show(WindowMain, msg, "提示信息");
- }
- }));
- }
- public void MessageBox(string msg)
- {
- DispatcherHelper.GetUIDispatcher().Invoke(new Action(() =>
- {
- System.Windows.MessageBox.Show(WindowMain, msg, "提示信息");
- }));
- }
- public void MessageBox(string msg, string strTitle)
- {
- DispatcherHelper.GetUIDispatcher().Invoke(new Action(() =>
- {
- System.Windows.MessageBox.Show(WindowMain, msg, "提示信息");
- }));
- }
- public void MessageBox(string msg, Action<bool> callback)
- {
- MessageBox("系统提示", msg, callback);
- }
- public void MessageBox(string title, string msg, Action<bool> callback)
- {
- DispatcherHelper.GetUIDispatcher().Invoke(new Action(() =>
- {
- if (System.Windows.MessageBox.Show(WindowMain, msg, title, MessageBoxButton.YesNo) == MessageBoxResult.Yes)
- {
- callback(true);
- }
- else
- {
- callback(false);
- }
- }));
- }
- #endregion
- #region 异步线程
- public void AsyncLoad(Action action)
- {
- IAsyncResult result = action.BeginInvoke((iar) =>
- {
- }, null);
- }
- public void AsyncLoad(Action action, Action callback)
- {
- IAsyncResult result = action.BeginInvoke((iar) =>
- {
- this.DoMenthodByDispatcher(callback);
- }, null);
- }
- public void AsyncLoad<T>(Action<T> action, T para, Action callback)
- {
- IAsyncResult result = action.BeginInvoke(para, (iar) =>
- {
- this.DoMenthodByDispatcher(callback);
- }, null);
- }
- public void AsyncLoad<T, R>(Func<T, R> action, T para, Action<R> callback)
- {
- IAsyncResult result = action.BeginInvoke(para, (iar) =>
- {
- var res = action.EndInvoke(iar);
- this.DoMenthodByDispatcher<R>(callback, res);
- }, null);
- }
- public void AsyncLoad<R>(Func<R> action, Action<R> callback)
- {
- IAsyncResult result = action.BeginInvoke((iar) =>
- {
- var res = action.EndInvoke(iar);
- this.DoMenthodByDispatcher<R>(callback, res);
- }, null);
- }
- public void DoMenthodByDispatcher<T>(Action<T> action, T obj)
- {
- DispatcherHelper.GetUIDispatcher().BeginInvoke(new Action(() =>
- {
- action(obj);
- }), DispatcherPriority.Normal);
- }
- public void DoMenthodByDispatcher(Action action)
- {
- DispatcherHelper.GetUIDispatcher().BeginInvoke(new Action(() =>
- {
- action();
- }), DispatcherPriority.Normal);
- }
- #endregion
- protected void OnPropertyChanged([CallerMemberName]string propertyName = "")
- {
- if (PropertyChanged != null)
- {
- PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
- }
- }
- }
- }
BaseViewModel 的代码如上所示, 主要实现了以下功能:
1,UI 元素 Window,Page,UserControl 的创建;
2, 基础窗体方法, 比如 Show,Close,Message 等等.
3, 一系列线程切换的异步操作.
4, 简洁化消息处理.(不理解的消息的可参看这篇文章 C# 语法 -- 消息, MVVM 的核心技术.)
--------------------------------------------------------------------------------------------------------------------------------
这样, BaseViewModel 就编写完成了, 之后我们一起修改 WPF 项目, 让窗体的启动的时候, 使用 ViewModel 启动.
在 WPF 项目中创建 WindowMain 窗体, 并在 VM 中创建对应的 ViewModel.
然后在 App.Xaml.cs 文件中重写启动函数, 代码如下:
protected override void OnStartup(StartupEventArgs e) { VM_WindowMain vm = new VM_WindowMain(); Application.Current.MainWindow = vm.UIElement as Window; vm.Show(); base.OnStartup(e); }
在删除 App.Xaml 的 StartupUri 属性.
这样运行 WPF 就会启动我们的 WindowMain 窗体了.
ViewModel 创建窗体
主窗体已经运行了, 如果我们想运行其他窗体, 该怎么做呢?
很简单, 只要在主窗体的 ViewModel 中 new 那个想要运行的窗体的 VM, 然后 Show 一下就可以了. 代码如下:
VM_WindowCreateUser vm = new VM_WindowCreateUser(); vm.Show();
到此, 窗体相关的内容我们已经一起编写完成了.
接下来需要编写的是 Page 和 UserControl 的基础使用方式.
但 Page 和 UserControl 是被 Window 使用的, 不能直接呈现, 所以, 在使用 Page 和 UserControl 之前, 我们需要编写 MVVM 框架中, 用于在 WPF 页面和 ViewModel 传递信息的 Command(命令).
本篇文章就先不介绍 Command 了, 敬请期待下一篇文章, 让我们一起继续完善我们的框架.
框架代码已经传到 Github 上了, 并且会持续更新.
To be continued
Github 地址: https://github.com/kiba518/KibaFramework
来源: https://www.cnblogs.com/kiba/p/9565299.html