阅读目录
1、介绍
2、核心搭建Core
3、框架完善
3.1、基础数据绑定
3.2、事件绑定
3.3、转换器使用
3.4、添加日志页
3.5、模型业务调用
3.6、切换可视页面
3.7、查询数据分页显示
4、框架使用
5、参考
返回系列文章目录
案例代码下载
1、介绍
MVVM(Model-View-ViewModel)是一种驱动可视化界面的事件为起点的软件架构模式,个人认为其是MVC的升级版。
上图是我们MVVM架构的组成,主要模块职责如下:
①Infrastructure:给MVVM模块做基础支持,存放一些数据获取模块,帮助模块,转换器和支持框架的文件。
②Models:是MVVM框架的业务处理部分,主要的业务逻辑都存放在这个模块。
③Views:存放和用户交互的相关窗口、页面和控件。
④ViewModels:主要是界面展示需要用到的数据,界面上命令的执行逻辑,调用Models模块业务。
2、核心搭建Core
我们这个框架的原理就是,Views对ViewModel属性的双向绑定 binding ,ViewModel数据更改后通知Views利用的是 INotifyPropertyChanged 接口。下面开始来搭建框架:
①先创建一个 WPF应用程序 Demo10A-Framework ,这就是框架的主要部分,Views 存放界面部分,主要存放Window、Page、UserControl及一些自定义的控件;ViewModels 存放界面交互的数据监听事件。
②分别创建框架的另外两个模块,选择 WPF类库 分别命名Demo10A-Models和Demo10A-Infrastructure。
③模块 Demo10A-Framework 里创建文件夹 Core,文件夹下创建ViewModel数据变更通知类NotificationObject.cs。
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Linq; 5 using System.Runtime.CompilerServices; 6 using System.Text; 7 using System.Threading.Tasks; 8 9 namespace Demo10A_Framework.Core 10 { 11 public class NotificationObject : INotifyPropertyChanged 12 { 13 public event PropertyChangedEventHandler PropertyChanged; 14 public void RaisePropertyChanged([CallerMemberName] string propertyName = "") 15 { 16 this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 17 } 18 } 19 }NotificationObject.cs
④模块 Demo10A-Framework 文件夹 Core 下创建跨线程帮助类DispatcherHelper.cs。
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Windows; 7 using System.Windows.Threading; 8 9 namespace Demo10A_Framework.Core 10 { 11 public class DispatcherHelper 12 { 13 public static Dispatcher GetUIDispatcher() 14 { 15 try 16 { 17 return Application.Current.MainWindow.Dispatcher; 18 } 19 catch 20 { 21 return null; 22 } 23 } 24 } 25 }DispatcherHelper.cs
⑤模块 Demo10A-Framework 文件夹 Core 下创建异步线程操作、消息弹窗、窗体操作和反射创建View的基础ViewModel类BaseViewModel.cs。
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Reflection; 5 using System.Text; 6 using System.Threading.Tasks; 7 using System.Windows; 8 using System.Windows.Controls; 9 using System.Windows.Threading; 10 11 namespace Demo10A_Framework.Core 12 { 13 public class BaseViewModel : NotificationObject 14 { 15 #region 基础属性 16 private static string _viewsAssemblyName;//Views程序集名 17 private static string _viewsNamespace;//Views名称空间 18 private Window _windowMain; //主窗体 19 public EventHandler CloseCallBack = null; //窗体/页面/控件 关闭委托 20 public FrameworkElement UIElement { get; set; } //UI元素 21 #endregion 22 23 #region 构造函数 24 public BaseViewModel() 25 { 26 _windowMain = Application.Current.MainWindow; 27 SetUIElement(); 28 29 //数据绑定 30 UIElement.DataContext = this; 31 } 32 public BaseViewModel(string viewsAssemblyName, string viewsNamespace) 33 { 34 _viewsAssemblyName = viewsAssemblyName; 35 _viewsNamespace = viewsNamespace; 36 37 _windowMain = Application.Current.MainWindow; 38 SetUIElement(); 39 40 //数据绑定 41 UIElement.DataContext = this; 42 } 43 #endregion 44 45 #region 通过反射创建对应的UI元素 46 public void SetUIElement() 47 { 48 Type childType = this.GetType();//获取子类的类型 49 var name = childType.Name; 50 name = name.Replace("Model", ""); 51 switch (name.First()) 52 { 53 case 'W': 54 UIElement = GetElement<Window>(name); 55 (UIElement as Window).Closing += (s, e) => 56 { 57 if (CloseCallBack != null) 58 { 59 CloseCallBack(s, e); 60 } 61 }; 62 break; 63 case 'P': 64 UIElement = GetElement<Page>(name); 65 (UIElement as Page).Unloaded += (s, e) => 66 { 67 if (CloseCallBack != null) 68 { 69 CloseCallBack(s, e); 70 } 71 }; 72 break; 73 case 'U': 74 UIElement = GetElement<UserControl>(name); 75 (UIElement as UserControl).Unloaded += (s, e) => 76 { 77 if (CloseCallBack != null) 78 { 79 CloseCallBack(s, e); 80 } 81 }; 82 break; 83 default: 84 throw new Exception("元素名不规范"); 85 86 } 87 88 89 90 } 91 92 public E GetElement<E>(string elementName) 93 { 94 Type type = GetFormType(_viewsNamespace + "." + elementName); 95 E element = (E)Activator.CreateInstance(type); 96 return element; 97 } 98 99 public Type GetFormType(string fullName) 100 { 101 Assembly assembly = Assembly.Load(_viewsAssemblyName); 102 Type type = assembly.GetType(fullName, true, false); 103 return type; 104 } 105 #endregion 106 107 #region 窗体操作 108 public void Show() 109 { 110 if (UIElement is Window) 111 { 112 (UIElement as Window).Show(); 113 } 114 else 115 { 116 throw new Exception("元素类型不正确"); 117 } 118 } 119 120 public void ShowDialog() 121 { 122 if (UIElement is Window) 123 { 124 (UIElement as Window).ShowDialog(); 125 } 126 else 127 { 128 throw new Exception("元素类型不正确"); 129 } 130 } 131 132 public void Close() 133 { 134 if (UIElement is Window) 135 { 136 (UIElement as Window).Close(); 137 } 138 else 139 { 140 throw new Exception("元素类型不正确"); 141 } 142 } 143 144 public void Hide() 145 { 146 if (UIElement is Window) 147 { 148 (UIElement as Window).Hide(); 149 } 150 else 151 { 152 throw new Exception("元素类型不正确"); 153 } 154 } 155 #endregion 156 157 #region 异步线程 158 public void AsyncLoad(Action action) 159 { 160 IAsyncResult result = action.BeginInvoke((iar) => 161 { 162 }, null); 163 } 164 165 public void AsyncLoad(Action action, Action callback) 166 { 167 IAsyncResult result = action.BeginInvoke((iar) => 168 { 169 this.DoMenthodByDispatcher(callback); 170 }, null); 171 } 172 173 public void AsyncLoad<T>(Action<T> action, T para, Action callback) 174 { 175 IAsyncResult result = action.BeginInvoke(para, (iar) => 176 { 177 this.DoMenthodByDispatcher(callback); 178 }, null); 179 } 180 181 public void AsyncLoad<T, R>(Func<T, R> action, T para, Action<R> callback) 182 { 183 IAsyncResult result = action.BeginInvoke(para, (iar) => 184 { 185 var res = action.EndInvoke(iar); 186 this.DoMenthodByDispatcher<R>(callback, res); 187 }, null); 188 } 189 190 public void AsyncLoad<R>(Func<R> action, Action<R> callback) 191 { 192 IAsyncResult result = action.BeginInvoke((iar) => 193 { 194 var res = action.EndInvoke(iar); 195 this.DoMenthodByDispatcher<R>(callback, res); 196 }, null); 197 } 198 199 public void DoMenthodByDispatcher<T>(Action<T> action, T obj) 200 { 201 DispatcherHelper.GetUIDispatcher().BeginInvoke(new Action(() => 202 { 203 action(obj); 204 }), DispatcherPriority.Normal); 205 } 206 207 public void DoMenthodByDispatcher(Action action) 208 { 209 DispatcherHelper.GetUIDispatcher().BeginInvoke(new Action(() => 210 { 211 action(); 212 }), DispatcherPriority.Normal); 213 } 214 #endregion 215 216 #region Message 217 public void MessageBox(Window owner, string msg) 218 { 219 DispatcherHelper.GetUIDispatcher().Invoke(new Action(() => 220 { 221 if (owner != null) 222 { 223 System.Windows.MessageBox.Show(owner, msg, "提示信息"); 224 } 225 else 226 { 227 System.Windows.MessageBox.Show(_windowMain, msg, "提示信息"); 228 } 229 })); 230 } 231 232 public void MessageBox(string msg) 233 { 234 DispatcherHelper.GetUIDispatcher().Invoke(new Action(() => 235 { 236 System.Windows.MessageBox.Show(_windowMain, msg, "提示信息"); 237 })); 238 } 239 240 public void MessageBox(string msg, string strTitle) 241 { 242 DispatcherHelper.GetUIDispatcher().Invoke(new Action(() => 243 { 244 System.Windows.MessageBox.Show(_windowMain, msg, "提示信息"); 245 })); 246 } 247 248 public void MessageBox(string msg, Action<bool> callback) 249 { 250 MessageBox("系统提示", msg, callback); 251 } 252 253 public void MessageBox(string title, string msg, Action<bool> callback) 254 { 255 DispatcherHelper.GetUIDispatcher().Invoke(new Action(() => 256 { 257 if (System.Windows.MessageBox.Show(_windowMain, msg, title, MessageBoxButton.YesNo) == MessageBoxResult.Yes) 258 { 259 callback(true); 260 } 261 else 262 { 263 callback(false); 264 } 265 })); 266 } 267 #endregion 268 269 } 270 }BaseViewModel.cs
⑥模块 Demo10A-Framework 文件夹 ViewModels 下创建欢迎页的ViewModel,WMainViewModel.cs。
1 using Demo10A_Framework.Core; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace Demo10A_Framework.ViewModels 9 { 10 public class WMainViewModel:BaseViewModel 11 { 12 public WMainViewModel(string pAssemblyName, string pNamespace):base(pAssemblyName, pNamespace) 13 { 14 15 } 16 } 17 }WMainViewModel.cs
⑦模块 Demo10A-Framework 文件夹 Views 下删除默认创建的主窗体MainWindow.xaml,新建项 窗口(WPF) 命名为 WMainView.xaml,打开App.xaml文件,删除XAML里引导入口代码 StartupUri="MainWindow.xaml" ,打开 App.xaml.cs ,添加引导代码及挂机全局异常处理的代码如下。
1 using Demo10A_Framework.Globals; 2 using Demo10A_Framework.ViewModels; 3 using System; 4 using System.Collections.Generic; 5 using System.Configuration; 6 using System.Data; 7 using System.Linq; 8 using System.Threading.Tasks; 9 using System.Windows; 10 using System.Windows.Threading; 11 12 namespace Demo10A_Framework 13 { 14 /// <summary> 15 /// App.xaml 的交互逻辑 16 /// </summary> 17 public partial class App : Application 18 { 19 protected override void OnStartup(StartupEventArgs e) 20 { 21 //配置项目的程序集名和名称空间,利用反射创建窗体 22 var mainViewModel = new WMainViewModel("Demo10A-Framework", "Demo10A_Framework.Views"); 23 GlobalVisualizedData.MainViewModel = mainViewModel; //保存到全局变量 24 Application.Current.MainWindow = mainViewModel.UIElement as Window; 25 mainViewModel.Show(); 26 base.OnStartup(e); 27 } 28 29 /// <summary> 30 /// 加载完成 31 /// </summary> 32 /// <param name="e"></param> 33 protected override void onl oadCompleted(System.Windows.Navigation.NavigationEventArgs e) 34 { 35 base.OnLoadCompleted(e); 36 Current.DispatcherUnhandledException += App_OnDispatcherUnhandledException; 37 AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; 38 } 39 40 /// <summary> 41 /// UI线程抛出全局异常事件处理 42 /// </summary> 43 /// <param name="sender"></param> 44 /// <param name="e"></param> 45 private void App_OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) 46 { 47 try 48 { 49 e.Handled = true; 50 } 51 catch (Exception ex) 52 { 53 } 54 } 55 56 /// <summary> 57 /// 非UI线程抛出全局异常事件处理 58 /// </summary> 59 /// <param name="sender"></param> 60 /// <param name="e"></param> 61 private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) 62 { 63 try 64 { 65 var exception = e.ExceptionObject as Exception; 66 if (exception != null) 67 { 68 } 69 } 70 catch (Exception ex) 71 { 72 } 73 } 74 } 75 }App.xaml.cs
1 <Application x:Class="Demo10A_Framework.App" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:local="clr-namespace:Demo10A_Framework" 5 > 6 <Application.Resources> 7 8 </Application.Resources> 9 </Application>App.xaml
1 <Window x:Class="Demo10A_Framework.Views.WMainView" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:Demo10A_Framework.Views" 7 mc:Ignorable="d" 8 Title="WMainView" Height="450" Width="800"> 9 <Grid> 10 <Frame x:Name="mainFrame" NavigationUIVisibility="Hidden"/> 11 </Grid> 12 </Window>WMainView.xaml
⑧模块 Demo10A-Framework 文件夹 Globals 下创建GlobalVisualizedData.cs,用来存放ViewModel直接操作View里面的元素逻辑。
1 using Demo10A_Framework.ViewModels; 2 using Demo10A_Framework.Views; 3 using System; 4 using System.Collections.Generic; 5 using System.Linq; 6 using System.Text; 7 using System.Threading.Tasks; 8 9 namespace Demo10A_Framework.Globals 10 { 11 public class GlobalVisualizedData 12 { 13 #region 全局主窗口ViewModel + public static WMainViewModel MainViewModel 14 private static WMainViewModel _mainViewModel; 15 16 public static WMainViewModel MainViewModel 17 { 18 get { return _mainViewModel; } 19 set { 20 _mainView = value.UIElement as WMainView; 21 _mainViewModel = value; } 22 } 23 #endregion 24 25 private static WMainView _mainView; //全局主窗口View 26 27 28 } 29 }GlobalVisualizedData.cs
⑨以上就已经完成了WPF下MVVM框架的核心代码,可以尝试运行一下。
3、框架完善
经过上面的步骤,基本的MVVM框架已经成型,以后我们就可以在这个框架上开发应用程序了,我建议可以做成SPA(单页面)应用,这样可以降低页面切换的很多额外工作。
3.1、基础数据绑定
这节我们来给框架创建一个欢迎窗口,欢迎界面3秒后自动关闭。
①模块 Demo10A-Framework 文件夹 ViewModels 下创建欢迎页的ViewModel,WWelcomeViewModel.cs。
1 using Demo10A_Framework.Core; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace Demo10A_Framework.ViewModels 9 { 10 public class WWelcomeViewModel:BaseViewModel 11 { 12 public WWelcomeViewModel() 13 { 14 } 15 public WWelcomeViewModel(string viewsAssemblyName, string viewsNamespace) : base(viewsAssemblyName, viewsNamespace) 16 { 17 } 18 } 19 }WWelcomeViewModel.cs
②模块 Demo10A-Framework 文件夹 Views 下创建欢迎页的View,WWelcomeView.xaml。
1 <Window x:Class="Demo10A_Framework.Views.WWelcomeView" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:Demo10A_Framework.Views" 7 mc:Ignorable="d" 8 Title="WWelcomeView" Height="450" Width="800" WindowStyle="None" ResizeMode="NoResize" WindowStartupLocation="CenterScreen" Cursor="Hand" > 9 <Grid VerticalAlignment="Center" HorizontalAlignment="Center"> 10 <TextBlock Text="欢迎页" FontSize="72"/> 11 </Grid> 12 </Window>WWelcomeView.xaml
③模块 Demo10A-Framework 文件夹 Globals 下更新GlobalVisualizedData.cs,加入更新主窗体标题的。
1 using Demo10A_Framework.ViewModels; 2 using Demo10A_Framework.Views; 3 using System; 4 using System.Collections.Generic; 5 using System.Linq; 6 using System.Text; 7 using System.Threading; 8 using System.Threading.Tasks; 9 using System.Windows; 10 11 namespace Demo10A_Framework.Globals 12 { 13 public class GlobalVisualizedData 14 { 15 private const string _viewsAssemblyName = "Demo10A-Framework"; 16 private const string _viewsNamespace = "Demo10A_Framework.Views"; 17 private static WMainViewModel _mainViewModel; //全局主窗口ViewModel 18 private static WMainView _mainWindowView; //全局主窗口View 19 20 public static void UseWelcomeWindow(bool isUseWelcomeWindow,int delayMilliseconds) 21 { 22 if (isUseWelcomeWindow) 23 { 24 _mainViewModel = new WMainViewModel(_viewsAssemblyName, _viewsNamespace); 25 _mainWindowView = _mainViewModel.UIElement as WMainView; 26 var welcome = new WWelcomeViewModel(); 27 welcome.Show(); 28 App.Current.Dispatcher.Invoke(() => 29 { //跨线程操作UI 30 Task.WaitAll(Task.Delay(delayMilliseconds)); 31 welcome.Close(); 32 _mainViewModel.Show(); 33 }); 34 } 35 else 36 { 37 _mainViewModel = new WMainViewModel(_viewsAssemblyName, _viewsNamespace); 38 _mainWindowView = _mainViewModel.UIElement as WMainView; 39 _mainViewModel.Show(); 40 } 41 } 42 } 43 }GlobalVisualizedData.cs
④模块 Demo10A-Framework 下文件App.xaml.cs,修改页面启动管理用GlobalVisualizedData控制。
1 using Demo10A_Framework.Globals; 2 using Demo10A_Framework.ViewModels; 3 using System; 4 using System.Collections.Generic; 5 using System.Configuration; 6 using System.Data; 7 using System.Linq; 8 using System.Threading.Tasks; 9 using System.Windows; 10 using System.Windows.Threading; 11 12 namespace Demo10A_Framework 13 { 14 /// <summary> 15 /// App.xaml 的交互逻辑 16 /// </summary> 17 public partial class App : Application 18 { 19 protected override void OnStartup(StartupEventArgs e) 20 { 21 GlobalVisualizedData.UseWelcomeWindow(true,3000); //初始化配置 22 base.OnStartup(e); 23 } 24 25 /// <summary> 26 /// 加载完成 27 /// </summary> 28 /// <param name="e"></param> 29 protected override void onl oadCompleted(System.Windows.Navigation.NavigationEventArgs e) 30 { 31 base.OnLoadCompleted(e); 32 Current.DispatcherUnhandledException += App_OnDispatcherUnhandledException; 33 AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; 34 } 35 36 /// <summary> 37 /// UI线程抛出全局异常事件处理 38 /// </summary> 39 /// <param name="sender"></param> 40 /// <param name="e"></param> 41 private void App_OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) 42 { 43 try 44 { 45 e.Handled = true; 46 } 47 catch (Exception ex) 48 { 49 } 50 } 51 52 /// <summary> 53 /// 非UI线程抛出全局异常事件处理 54 /// </summary> 55 /// <param name="sender"></param> 56 /// <param name="e"></param> 57 private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) 58 { 59 try 60 { 61 var exception = e.ExceptionObject as Exception; 62 if (exception != null) 63 { 64 } 65 } 66 catch (Exception ex) 67 { 68 } 69 } 70 } 71 }App.xaml.cs
⑤以上就完成了从欢迎页停留3秒后转入主窗口。
3.2、事件绑定
这节我们来编写事件绑定的相关代码,做一个按钮按下弹出消息框的案例。
①模块 Demo10A-Framework 文件夹 ViewModels 下创建系统页的ViewModel,PSystemViewModel.cs。
1 using Demo10A_Framework.Core; 2 using Demo10A_Framework.Globals; 3 using System; 4 using System.Collections.Generic; 5 using System.Linq; 6 using System.Text; 7 using System.Threading.Tasks; 8 9 namespace Demo10A_Framework.ViewModels 10 { 11 public class PSystemViewModel:BaseViewModel 12 { 13 #region 事件-消息框 + public DelegateCommand CallMessageBoxCommand 14 public DelegateCommand CallMessageBoxCommand 15 { 16 get 17 { 18 return new DelegateCommand(CallMessageBoxCommand_Executed); 19 } 20 } 21 22 private void CallMessageBoxCommand_Executed(object obj) 23 { 24 MessageBox("快捷支付多份心,莫名中奖少顿惜。 网购陷阱花样多,线上交易要当心。", "防诈提醒"); 25 } 26 #endregion 27 28 #region 构造函数 + public PSystemViewModel() 29 public PSystemViewModel() 30 { 31 GlobalVisualizedData.SetMainWindowTitle("系统主页[BigBox777]"); 32 } 33 #endregion 34 } 35 }PSystemViewModel.cs
②模块 Demo10A-Framework 文件夹 Views 下创建系统页的View,PSystemView.xaml。
1 <Page x:Class="Demo10A_Framework.Views.PSystemView" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 5 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 6 xmlns:local="clr-namespace:Demo10A_Framework.Views" 7 mc:Ignorable="d" 8 d:DesignHeight="450" d:DesignWidth="800" 9 Title="PSystemView"> 10 11 <Grid> 12 <Grid.ColumnDefinitions> 13 <ColumnDefinition Width="250"/> 14 <ColumnDefinition/> 15 </Grid.ColumnDefinitions> 16 <Border Margin="1,0,0,1" Grid.Column="0" BorderThickness="1,1,1,1" BorderBrush="Black"> 17 <StackPanel> 18 <Button Height="30" Content="弹出消息框" Command="{Binding CallMessageBoxCommand}"/> 19 <Button Height="30" Content="改变窗口标题"/> 20 <Button Height="30" Content="切换页面"/> 21 <Button Height="30" Content="创建新窗口"/> 22 <Button Height="30" Content="关闭新窗口"/> 23 <Button Height="30" Content="转换器使用"/> 24 <Border Margin="0" Padding="1,1,1,1" BorderThickness="1,1,1,1" BorderBrush="Red"> 25 <Grid Height="80"> 26 <Grid.ColumnDefinitions> 27 <ColumnDefinition Width="50"/> 28 <ColumnDefinition/> 29 </Grid.ColumnDefinitions> 30 <Grid.RowDefinitions> 31 <RowDefinition/> 32 <RowDefinition/> 33 <RowDefinition/> 34 </Grid.RowDefinitions> 35 36 <TextBlock Text="用户名:" VerticalAlignment="Center"/> 37 <TextBox Text="BigBox777" Grid.Column="1" VerticalAlignment="Center"/> 38 <TextBlock Text="密码:" Grid.Row="1" VerticalAlignment="Center"/> 39 <PasswordBox Password="12345" Grid.Row="1" Grid.Column="1" VerticalAlignment="Center"/> 40 <Button Content="登录" Grid.Row="2" Grid.ColumnSpan="2"/> 41 </Grid> 42 </Border> 43 <Button Height="30" Content="分页显示"/> 44 </StackPanel> 45 </Border> 46 <Frame Grid.Column="1"> 47 <Frame.Background> 48 <VisualBrush Stretch="Uniform" Opacity="0.5" Viewbox="-1,-1,3,3"> 49 <VisualBrush.Visual> 50 <TextBlock Text="BigBox777"/> 51 </VisualBrush.Visual> 52 </VisualBrush> 53 </Frame.Background> 54 </Frame> 55 </Grid> 56 </Page>PSystemView.xaml
③模块 Demo10A-Framework 文件夹 Globals 下更新GlobalVisualizedData.cs,加入更新系统页管理代码。
1 using Demo10A_Framework.ViewModels; 2 using Demo10A_Framework.Views; 3 using System; 4 using System.Collections.Generic; 5 using System.Linq; 6 using System.Text; 7 using System.Threading; 8 using System.Threading.Tasks; 9 using System.Windows; 10 11 namespace Demo10A_Framework.Globals 12 { 13 public class GlobalVisualizedData 14 { 15 #region 常量-Views配置信息 16 private const string _viewsAssemblyName = "Demo10A-Framework"; 17 private const string _viewsNamespace = "Demo10A_Framework.Views"; 18 #endregion 19 #region 全局-ViewModel信息 20 private static WMainViewModel _mainViewModel; //全局主窗口ViewModel 21 private static PSystemViewModel _systemViewModel; //全局系统页ViewModel 22 #endregion 23 24 #region 使用欢迎页 + public static void UseWelcomeWindow(bool isUseWelcomeWindow, int delayMilliseconds) 25 public static void UseWelcomeWindow(bool isUseWelcomeWindow, int delayMilliseconds) 26 { 27 if (isUseWelcomeWindow) 28 { 29 _mainViewModel = new WMainViewModel(_viewsAssemblyName, _viewsNamespace); 30 var welcome = new WWelcomeViewModel(); 31 welcome.Show(); 32 App.Current.Dispatcher.Invoke(() => 33 { //跨线程操作UI 34 Task.WaitAll(Task.Delay(delayMilliseconds)); 35 welcome.Close(); 36 ShowMainView(); 37 }); 38 } 39 else 40 { 41 _mainViewModel = new WMainViewModel(_viewsAssemblyName, _viewsNamespace); 42 ShowMainView(); 43 } 44 45 } 46 private static void ShowMainView() 47 { 48 _mainViewModel.Show(); 49 _systemViewModel = new PSystemViewModel(); 50 _mainViewModel.MainFrameNavigation(_systemViewModel.UIElement as PSystemView); 51 } 52 #endregion 53 54 #region 设置主窗体标题 + public static void SetMainWindowTitle(string title) 55 public static void SetMainWindowTitle(string title) 56 { 57 _mainViewModel.WindowTitle = title; 58 } 59 #endregion 60 61 62 } 63 }GlobalVisualizedData.cs
④以上就完成了按钮按下弹出消息框的案例。
3.3、转换器使用
①模块 Demo10A-Framework 文件夹 Converters 下创建需要使用的转换器代码ConvertChangeState2EllipseFill.cs。
1 using System; 2 using System.Collections.Generic; 3 using System.Globalization; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 using System.Windows; 8 using System.Windows.Data; 9 using System.Windows.Media; 10 11 namespace Demo10A_Framework.Converters 12 { 13 public class ConvertChangeState2EllipseFill : IValueConverter 14 { 15 //当值从绑定源传播给绑定目标时,调用方法Convert 16 public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 17 { 18 if (value == null || !(value is bool)) 19 { 20 throw new Exception(); 21 } 22 else 23 { 24 var state = (bool)value; 25 var str = parameter as string; 26 if (state) 27 { 28 if (str == "1") 29 { 30 return Brushes.Red; 31 } 32 else if (str == "2") 33 { 34 return Brushes.Blue; 35 } 36 else 37 { 38 return Brushes.Yellow; 39 } 40 } 41 else 42 { 43 if (str == "1") 44 { 45 return Brushes.Orange; 46 } 47 else if (str == "2") 48 { 49 return Brushes.DeepSkyBlue; 50 } 51 else 52 { 53 return Brushes.YellowGreen; 54 } 55 } 56 57 } 58 59 } 60 61 //当值从绑定目标传播给绑定源时,调用此方法ConvertBack 62 public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 63 { 64 return DependencyProperty.UnsetValue; 65 } 66 } 67 }ConvertChangeState2EllipseFill.cs
②模块 Demo10A-Framework 文件夹 Views 下更新系统页的View,PSystemView.xaml。
1 <Page x:Class="Demo10A_Framework.Views.PSystemView" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 5 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 6 xmlns:local="clr-namespace:Demo10A_Framework.Views" xmlns:converters="clr-namespace:Demo10A_Framework.Converters" 7 mc:Ignorable="d" 8 d:DesignHeight="450" d:DesignWidth="800" 9 Title="PSystemView"> 10 <Page.Resources> 11 <converters:ConvertChangeState2EllipseFill x:Key="changeStateConvert"/> 12 </Page.Resources> 13 <Grid> 14 <Grid.ColumnDefinitions> 15 <ColumnDefinition Width="250"/> 16 <ColumnDefinition/> 17 </Grid.ColumnDefinitions> 18 <Border Margin="1,0,0,1" Grid.Column="0" BorderThickness="1,1,1,1" BorderBrush="Black"> 19 <StackPanel> 20 <Button Height="30" Content="弹出消息框" Command="{Binding CallMessageBoxCommand}"/> 21 <Border Margin="0" Padding="1,1,1,1" BorderThickness="1,1,1,1" BorderBrush="Red"> 22 <Grid Height="60"> 23 <Grid.ColumnDefinitions> 24 <ColumnDefinition Width="60"/> 25 <ColumnDefinition/> 26 </Grid.ColumnDefinitions> 27 <Grid.RowDefinitions> 28 <RowDefinition/> 29 <RowDefinition/> 30 </Grid.RowDefinitions> 31 <TextBlock Text="窗口标题:" VerticalAlignment="Center"/> 32 <TextBox Text="{Binding SystemTitle}" Grid.Column="1" VerticalAlignment="Center"/> 33 <Button Content="改变窗口标题" Command="{Binding ChangeWindowTitleCommand}" Grid.Row="1" Grid.ColumnSpan="2"/> 34 </Grid> 35 </Border> 36 <Border Margin="0" Padding="1,1,1,1" BorderThickness="1,1,1,1" BorderBrush="Red"> 37 <Grid Height="60"> 38 <Grid.RowDefinitions> 39 <RowDefinition/> 40 <RowDefinition/> 41 </Grid.RowDefinitions> 42 <StackPanel Grid.Column="1" VerticalAlignment="Center" Orientation="Horizontal"> 43 <Ellipse Width="28" Height="28" Fill="{Binding EllipseState,Converter={StaticResource changeStateConvert}}" Margin="0,0,5,0"/> 44 <Ellipse Width="28" Height="28" Fill="{Binding EllipseState,Converter={StaticResource changeStateConvert}}" Margin="0,0,5,0"/> 45 <Ellipse Width="28" Height="28" Fill="{Binding EllipseState,Converter={StaticResource changeStateConvert},ConverterParameter='1'}" Margin="0,0,5,0"/> 46 <Ellipse Width="28" Height="28" Fill="{Binding EllipseState,Converter={StaticResource changeStateConvert},ConverterParameter='1'}" Margin="0,0,5,0"/> 47 <Ellipse Width="28" Height="28" Fill="{Binding EllipseState,Converter={StaticResource changeStateConvert},ConverterParameter='2'}" Margin="0,0,5,0"/> 48 <Ellipse Width="28" Height="28" Fill="{Binding EllipseState,Converter={StaticResource changeStateConvert},ConverterParameter='2'}" Margin="0,0,5,0"/> 49 </StackPanel> 50 <Button Content="转换器使用" Command="{Binding UseConverterCommand}" Grid.Row="1" Grid.ColumnSpan="2"/> 51 </Grid> 52 </Border> 53 <Button Height="30" Content="切换页面"/> 54 <Button Height="30" Content="创建新窗口"/> 55 <Button Height="30" Content="关闭新窗口"/> 56 <Border Margin="0" Padding="1,1,1,1" BorderThickness="1,1,1,1" BorderBrush="Red"> 57 <Grid Height="80"> 58 <Grid.ColumnDefinitions> 59 <ColumnDefinition Width="60"/> 60 <ColumnDefinition/> 61 </Grid.ColumnDefinitions> 62 <Grid.RowDefinitions> 63 <RowDefinition/> 64 <RowDefinition/> 65 <RowDefinition/> 66 </Grid.RowDefinitions> 67 68 <TextBlock Text="用户名:" VerticalAlignment="Center"/> 69 <TextBox Text="BigBox777" Grid.Column="1" VerticalAlignment="Center"/> 70 <TextBlock Text="密码:" Grid.Row="1" VerticalAlignment="Center"/> 71 <PasswordBox Password="12345" Grid.Row="1" Grid.Column="1" VerticalAlignment="Center"/> 72 <Button Content="登录" Grid.Row="2" Grid.ColumnSpan="2"/> 73 </Grid> 74 </Border> 75 <Button Height="30" Content="分页显示"/> 76 </StackPanel> 77 </Border> 78 <Frame Grid.Column="1"> 79 <Frame.Background> 80 <VisualBrush Stretch="Uniform" Opacity="0.5" Viewbox="-1,-1,3,3"> 81 <VisualBrush.Visual> 82 <TextBlock Text="BigBox777"/> 83 </VisualBrush.Visual> 84 </VisualBrush> 85 </Frame.Background> 86 </Frame> 87 </Grid> 88 </Page>PSystemView.xaml
③模块 Demo10A-Framework 文件夹 ViewModels 下创建系统页的ViewModel,PSystemViewModel.cs。
1 using Demo10A_Framework.Core; 2 using Demo10A_Framework.Globals; 3 using System; 4 using System.Collections.Generic; 5 using System.Linq; 6 using System.Text; 7 using System.Threading.Tasks; 8 9 namespace Demo10A_Framework.ViewModels 10 { 11 public class PSystemViewModel:BaseViewModel 12 { 13 #region 事件-消息框 + public DelegateCommand CallMessageBoxCommand 14 public DelegateCommand CallMessageBoxCommand 15 { 16 get 17 { 18 return new DelegateCommand(CallMessageBoxCommand_Executed); 19 } 20 } 21 22 private void CallMessageBoxCommand_Executed(object obj) 23 { 24 MessageBox("快捷支付多份心,莫名中奖少顿惜。 网购陷阱花样多,线上交易要当心。", "防诈提醒"); 25 } 26 #endregion 27 28 #region 属性-系统标题 + public string SystemTitle 29 private string _systemTitle = "系统窗口"; 30 public string SystemTitle 31 { 32 get { return _systemTitle; } 33 set 34 { 35 _systemTitle = value; 36 RaisePropertyChanged(); 37 } 38 } 39 #endregion 40 41 #region 事件-更改标题 + public DelegateCommand ChangeWindowTitleCommand 42 public DelegateCommand ChangeWindowTitleCommand 43 { 44 get 45 { 46 return new DelegateCommand(ChangeWindowTitleCommand_Executed); 47 } 48 } 49 50 private void ChangeWindowTitleCommand_Executed(object obj) 51 { 52 GlobalVisualizedData.SetMainWindowTitle(SystemTitle); 53 } 54 #endregion 55 56 #region 属性-圆状态 + public bool EllipseState 57 private bool _ellipseState; 58 59 public bool EllipseState 60 { 61 get { return _ellipseState; } 62 set 63 { 64 _ellipseState = value; 65 RaisePropertyChanged(); 66 } 67 } 68 #endregion 69 70 71 #region 事件-转换器使用 + public DelegateCommand UseConverterCommand 72 public DelegateCommand UseConverterCommand 73 { 74 get 75 { 76 return new DelegateCommand(UseConverterCommand_Executed); 77 } 78 } 79 80 private void UseConverterCommand_Executed(object obj) 81 { 82 EllipseState = !EllipseState; 83 } 84 #endregion 85 86 #region 构造函数 + public PSystemViewModel() 87 public PSystemViewModel() 88 { 89 GlobalVisualizedData.SetMainWindowTitle("系统主页[BigBox777]"); 90 } 91 #endregion 92 } 93 }PSystemViewModel.cs
④以上就完成了转换器和带参数的转换器案例。
3.4、添加日志页
这节我们把系统页面上的导航用起来,在第一个页面里面放一个textBox,放一些日志,并实现假数据的查询。
①模块 Demo10A-Framework 文件夹 ViewModels 下创建日志页的ViewModel,PLoggerViewModel.cs。
1 using Demo10A_Framework.Core; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace Demo10A_Framework.ViewModels 9 { 10 public class PLoggerViewModel:BaseViewModel 11 { 12 #region 属性-日志内容 + public string LogContent 13 private string _logContent; 14 15 public string LogContent 16 { 17 get { return _logContent; } 18 set 19 { 20 _logContent = value; 21 RaisePropertyChanged(); 22 } 23 } 24 #endregion 25 26 private StringBuilder _stringBuilder = new StringBuilder(); 27 #region 构造函数 + public PLoggerViewModel() 28 public PLoggerViewModel() 29 { 30 31 } 32 #endregion 33 34 #region 写日志 + public void WriteLog(Type type,string content) 35 public void WriteLog(Type type,string content) 36 { 37 _stringBuilder.AppendLine(string.Format("{0}[{1}]: {2}", type.FullName, DateTime.UtcNow, content)); 38 LogContent = _stringBuilder.ToString(); 39 } 40 #endregion 41 } 42 }PLoggerViewModel.cs
②模块 Demo10A-Framework 文件夹 Views 下创建日志页的View,PLoggerView.xaml。
1 <Page x:Class="Demo10A_Framework.Views.PLoggerView" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 5 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 6 xmlns:local="clr-namespace:Demo10A_Framework.Views" 7 mc:Ignorable="d" 8 d:DesignHeight="450" d:DesignWidth="800" 9 Title="PLoggerView"> 10 11 <Grid> 12 <TextBox Text="{Binding LogContent}" Margin="1" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"/> 13 </Grid> 14 </Page>PLoggerView.xaml
③模块 Demo10A-Framework 文件夹 Globals 下更新GlobalVisualizedData.cs,加入初始化日志页代码和写日志方法。
1 using Demo10A_Framework.ViewModels; 2 using Demo10A_Framework.Views; 3 using System; 4 using System.Collections.Generic; 5 using System.Linq; 6 using System.Text; 7 using System.Threading; 8 using System.Threading.Tasks; 9 using System.Windows; 10 11 namespace Demo10A_Framework.Globals 12 { 13 public class GlobalVisualizedData 14 { 15 #region 常量-Views配置信息 16 private const string _viewsAssemblyName = "Demo10A-Framework"; 17 private const string _viewsNamespace = "Demo10A_Framework.Views"; 18 #endregion 19 #region 全局-ViewModel信息 20 private static WMainViewModel _mainViewModel; //全局主窗口ViewModel 21 private static PSystemViewModel _systemViewModel; //全局系统页ViewModel 22 private static PLoggerViewModel _loggerViewModel; //全局Logger页ViewModel 23 #endregion 24 25 #region 使用欢迎页 + public static void UseWelcomeWindow(bool isUseWelcomeWindow, int delayMilliseconds) 26 public static void UseWelcomeWindow(bool isUseWelcomeWindow, int delayMilliseconds) 27 { 28 if (isUseWelcomeWindow) 29 { 30 _mainViewModel = new WMainViewModel(_viewsAssemblyName, _viewsNamespace); 31 var welcome = new WWelcomeViewModel(); 32 welcome.Show(); 33 App.Current.Dispatcher.Invoke(() => 34 { //跨线程操作UI 35 Task.WaitAll(Task.Delay(delayMilliseconds)); 36 welcome.Close(); 37 ShowMainView(); 38 }); 39 } 40 else 41 { 42 _mainViewModel = new WMainViewModel(_viewsAssemblyName, _viewsNamespace); 43 ShowMainView(); 44 } 45 46 } 47 private static void ShowMainView() 48 { 49 _mainViewModel.Show(); 50 _systemViewModel = new PSystemViewModel(); 51 _mainViewModel.MainFrameNavigation(_systemViewModel.UIElement as PSystemView); 52 _loggerViewModel = new PLoggerViewModel(); 53 _systemViewModel.SystemFrameNavigation(_loggerViewModel.UIElement as PLoggerView); 54 } 55 #endregion 56 57 #region 设置主窗体标题 + public static void SetMainWindowTitle(string title) 58 public static void SetMainWindowTitle(string title) 59 { 60 _mainViewModel.WindowTitle = title; 61 } 62 #endregion 63 64 #region 写日志 + public static void WriteLog(Type type,string content) 65 public static void WriteLog(Type type, string content) 66 { 67 _loggerViewModel.WriteLog(type,content); 68 } 69 #endregion 70 } 71 }GlobalVisualizedData.cs
④模块 Demo10A-Framework 文件夹 ViewModels 下更新系统页的ViewModel,PSystemViewModel.cs对操作动作记录到日志。
1 using Demo10A_Framework.Core; 2 using Demo10A_Framework.Globals; 3 using Demo10A_Framework.Views; 4 using System; 5 using System.Collections.Generic; 6 using System.Linq; 7 using System.Text; 8 using System.Threading.Tasks; 9 using System.Windows; 10 11 namespace Demo10A_Framework.ViewModels 12 { 13 public class PSystemViewModel:BaseViewModel 14 { 15 #region 事件-消息框 + public DelegateCommand CallMessageBoxCommand 16 public DelegateCommand CallMessageBoxCommand 17 { 18 get 19 { 20 return new DelegateCommand(CallMessageBoxCommand_Executed); 21 } 22 } 23 24 private void CallMessageBoxCommand_Executed(object obj) 25 { 26 GlobalVisualizedData.WriteLog(typeof(PSystemViewModel), string.Format("创建消息提示框,消息标题:{0},消息:{1}", "防诈提醒", "快捷支付多份心,莫名中奖少顿惜。 网购陷阱花样多,线上交易要当心。")); 27 MessageBox("快捷支付多份心,莫名中奖少顿惜。 网购陷阱花样多,线上交易要当心。", "防诈提醒"); 28 } 29 #endregion 30 31 #region 属性-系统标题 + public string SystemTitle 32 private string _systemTitle = "系统窗口"; 33 public string SystemTitle 34 { 35 get { return _systemTitle; } 36 set 37 { 38 _systemTitle = value; 39 RaisePropertyChanged(); 40 } 41 } 42 #endregion 43 44 #region 事件-更改标题 + public DelegateCommand ChangeWindowTitleCommand 45 public DelegateCommand ChangeWindowTitleCommand 46 { 47 get 48 { 49 return new DelegateCommand(ChangeWindowTitleCommand_Executed); 50 } 51 } 52 53 private void ChangeWindowTitleCommand_Executed(object obj) 54 { 55 GlobalVisualizedData.WriteLog(typeof(PSystemViewModel), string.Format("更改主窗口标题,SystemTitle={0}", SystemTitle)); 56 GlobalVisualizedData.SetMainWindowTitle(SystemTitle); 57 } 58 #endregion 59 60 #region 属性-圆状态 + public bool EllipseState 61 private bool _ellipseState; 62 63 public bool EllipseState 64 { 65 get { return _ellipseState; } 66 set 67 { 68 _ellipseState = value; 69 RaisePropertyChanged(); 70 } 71 } 72 #endregion 73 74 #region 事件-转换器使用 + public DelegateCommand UseConverterCommand 75 public DelegateCommand UseConverterCommand 76 { 77 get 78 { 79 return new DelegateCommand(UseConverterCommand_Executed); 80 } 81 } 82 83 private void UseConverterCommand_Executed(object obj) 84 { 85 GlobalVisualizedData.WriteLog(typeof(PSystemViewModel), string.Format("使用转换器更改圆状态,EllipseState={0}", EllipseState)); 86 EllipseState = !EllipseState; 87 } 88 #endregion 89 90 #region 构造函数 + public PSystemViewModel() 91 public PSystemViewModel() 92 { 93 GlobalVisualizedData.SetMainWindowTitle("系统主页[BigBox777]"); 94 } 95 #endregion 96 97 #region 系统Frame导航 + public void SystemFrameNavigation(FrameworkElement element) 98 public void SystemFrameNavigation(FrameworkElement element) 99 { 100 (UIElement as PSystemView).systemFrame.Navigate(element); 101 } 102 #endregion 103 } 104 }PSystemViewModel.cs
⑤完成上面步骤已经完成了添加日志页功能。
3.5、模型业务调用
这节来做一个模型里面业务用户登录的案例。
①模块 Demo10A-Framework 文件夹 Views 下更新系统页的View,添加登录界面。
1 <Page x:Class="Demo10A_Framework.Views.PSystemView" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 5 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 6 xmlns:local="clr-namespace:Demo10A_Framework.Views" xmlns:converters="clr-namespace:Demo10A_Framework.Converters" 7 mc:Ignorable="d" 8 d:DesignHeight="450" d:DesignWidth="800" 9 Title="PSystemView"> 10 <Page.Resources> 11 <converters:ConvertChangeState2EllipseFill x:Key="changeStateConvert"/> 12 </Page.Resources> 13 <Grid> 14 <Grid.ColumnDefinitions> 15 <ColumnDefinition Width="250"/> 16 <ColumnDefinition/> 17 </Grid.ColumnDefinitions> 18 <Border Margin="1,0,0,1" Grid.Column="0" BorderThickness="1,1,1,1" BorderBrush="Black"> 19 <StackPanel> 20 <Button Height="30" Content="弹出消息框" Command="{Binding CallMessageBoxCommand}"/> 21 <Border Margin="0" Padding="1,1,1,1" BorderThickness="1,1,1,1" BorderBrush="Red"> 22 <Grid Height="60"> 23 <Grid.ColumnDefinitions> 24 <ColumnDefinition Width="60"/> 25 <ColumnDefinition/> 26 </Grid.ColumnDefinitions> 27 <Grid.RowDefinitions> 28 <RowDefinition/> 29 <RowDefinition/> 30 </Grid.RowDefinitions> 31 <TextBlock Text="窗口标题:" VerticalAlignment="Center"/> 32 <TextBox Text="{Binding SystemTitle}" Grid.Column="1" VerticalAlignment="Center"/> 33 <Button Content="改变窗口标题" Command="{Binding ChangeWindowTitleCommand}" Grid.Row="1" Grid.ColumnSpan="2"/> 34 </Grid> 35 </Border> 36 <Border Margin="0" Padding="1,1,1,1" BorderThickness="1,1,1,1" BorderBrush="Red"> 37 <Grid Height="60"> 38 <Grid.RowDefinitions> 39 <RowDefinition/> 40 <RowDefinition/> 41 </Grid.RowDefinitions> 42 <StackPanel Grid.Column="1" VerticalAlignment="Center" Orientation="Horizontal"> 43 <Ellipse Width="28" Height="28" Fill="{Binding EllipseState,Converter={StaticResource changeStateConvert}}" Margin="0,0,5,0"/> 44 <Ellipse Width="28" Height="28" Fill="{Binding EllipseState,Converter={StaticResource changeStateConvert}}" Margin="0,0,5,0"/> 45 <Ellipse Width="28" Height="28" Fill="{Binding EllipseState,Converter={StaticResource changeStateConvert},ConverterParameter='1'}" Margin="0,0,5,0"/> 46 <Ellipse Width="28" Height="28" Fill="{Binding EllipseState,Converter={StaticResource changeStateConvert},ConverterParameter='1'}" Margin="0,0,5,0"/> 47 <Ellipse Width="28" Height="28" Fill="{Binding EllipseState,Converter={StaticResource changeStateConvert},ConverterParameter='2'}" Margin="0,0,5,0"/> 48 <Ellipse Width="28" Height="28" Fill="{Binding EllipseState,Converter={StaticResource changeStateConvert},ConverterParameter='2'}" Margin="0,0,5,0"/> 49 </StackPanel> 50 <Button Content="转换器使用" Command="{Binding UseConverterCommand}" Grid.Row="1" Grid.ColumnSpan="2"/> 51 </Grid> 52 </Border> 53 <Button Height="30" Content="创建新窗口"/> 54 <Button Height="30" Content="关闭新窗口"/> 55 <Border Margin="0" Padding="1,1,1,1" BorderThickness="1,1,1,1" BorderBrush="Red"> 56 <Grid Height="80"> 57 <Grid.ColumnDefinitions> 58 <ColumnDefinition Width="60"/> 59 <ColumnDefinition/> 60 </Grid.ColumnDefinitions> 61 <Grid.RowDefinitions> 62 <RowDefinition/> 63 <RowDefinition/> 64 <RowDefinition/> 65 </Grid.RowDefinitions> 66 67 <TextBlock Text="用户名:" VerticalAlignment="Center"/> 68 <TextBox Text="{Binding UserName}" Grid.Column="1" VerticalAlignment="Center"/> 69 <TextBlock Text="密码:" Grid.Row="1" VerticalAlignment="Center"/> 70 <TextBox Text="{Binding PWD}" Grid.Row="1" Grid.Column="1" VerticalAlignment="Center"/> 71 <Button Content="登录" Command="{Binding LoginCommand}" Grid.Row="2" Grid.ColumnSpan="2"/> 72 </Grid> 73 </Border> 74 <Button Height="30" Content="切换页面"/> 75 <Button Height="30" Content="分页显示"/> 76 </StackPanel> 77 </Border> 78 <Frame x:Name="systemFrame" Grid.Column="1"> 79 <Frame.Background> 80 <VisualBrush Stretch="Uniform" Opacity="0.5" Viewbox="-1,-1,3,3"> 81 <VisualBrush.Visual> 82 <TextBlock Text="BigBox777"/> 83 </VisualBrush.Visual> 84 </VisualBrush> 85 </Frame.Background> 86 </Frame> 87 </Grid> 88 </Page>PSystemView.xaml
②模块 Demo10A-Framework 文件夹 ViewModels 下更新系统页的ViewModel,添加登录的命令和属性绑定。
1 using Demo10A_Framework.Core; 2 using Demo10A_Framework.Globals; 3 using Demo10A_Framework.Views; 4 using Demo10A_Models; 5 using System; 6 using System.Collections.Generic; 7 using System.Linq; 8 using System.Text; 9 using System.Threading.Tasks; 10 using System.Windows; 11 12 namespace Demo10A_Framework.ViewModels 13 { 14 public class PSystemViewModel:BaseViewModel 15 { 16 #region 事件-消息框 + public DelegateCommand CallMessageBoxCommand 17 public DelegateCommand CallMessageBoxCommand 18 { 19 get 20 { 21 return new DelegateCommand(CallMessageBoxCommand_Executed); 22 } 23 } 24 25 private void CallMessageBoxCommand_Executed(object obj) 26 { 27 GlobalVisualizedData.WriteLog(typeof(PSystemViewModel), string.Format("创建消息提示框,消息标题:{0},消息:{1}", "防诈提醒", "快捷支付多份心,莫名中奖少顿惜。 网购陷阱花样多,线上交易要当心。")); 28 MessageBox("快捷支付多份心,莫名中奖少顿惜。 网购陷阱花样多,线上交易要当心。", "防诈提醒"); 29 } 30 #endregion 31 32 #region 属性-系统标题 + public string SystemTitle 33 private string _systemTitle = "系统窗口"; 34 public string SystemTitle 35 { 36 get { return _systemTitle; } 37 set 38 { 39 _systemTitle = value; 40 RaisePropertyChanged(); 41 } 42 } 43 #endregion 44 45 #region 事件-更改标题 + public DelegateCommand ChangeWindowTitleCommand 46 public DelegateCommand ChangeWindowTitleCommand 47 { 48 get 49 { 50 return new DelegateCommand(ChangeWindowTitleCommand_Executed); 51 } 52 } 53 54 private void ChangeWindowTitleCommand_Executed(object obj) 55 { 56 GlobalVisualizedData.WriteLog(typeof(PSystemViewModel), string.Format("更改主窗口标题,SystemTitle={0}", SystemTitle)); 57 GlobalVisualizedData.SetMainWindowTitle(SystemTitle); 58 } 59 #endregion 60 61 #region 属性-圆状态 + public bool EllipseState 62 private bool _ellipseState; 63 64 public bool EllipseState 65 { 66 get { return _ellipseState; } 67 set 68 { 69 _ellipseState = value; 70 RaisePropertyChanged(); 71 } 72 } 73 #endregion 74 75 #region 事件-转换器使用 + public DelegateCommand UseConverterCommand 76 public DelegateCommand UseConverterCommand 77 { 78 get 79 { 80 return new DelegateCommand(UseConverterCommand_Executed); 81 } 82 } 83 84 private void UseConverterCommand_Executed(object obj) 85 { 86 GlobalVisualizedData.WriteLog(typeof(PSystemViewModel), string.Format("使用转换器更改圆状态,EllipseState={0}", EllipseState)); 87 EllipseState = !EllipseState; 88 } 89 #endregion 90 91 #region 属性-用户名 + public string UserName 92 private string _userName = "BigBox777"; 93 public string UserName 94 { 95 get { return _userName; } 96 set 97 { 98 _userName = value; 99 RaisePropertyChanged(); 100 } 101 } 102 #endregion 103 104 #region 属性-密码 + public string PWD 105 private string _PWD = "12345"; 106 public string PWD 107 { 108 get { return _PWD; } 109 set 110 { 111 _PWD = value; 112 RaisePropertyChanged(); 113 } 114 } 115 #endregion 116 117 #region 事件-登录 + public DelegateCommand LoginCommand 118 public DelegateCommand LoginCommand 119 { 120 get 121 { 122 return new DelegateCommand(LoginCommand_Executed); 123 } 124 } 125 126 private void LoginCommand_Executed(object obj) 127 { 128 129 var result = UserInfo.Login(UserName,PWD); 130 GlobalVisualizedData.WriteLog(typeof(PSystemViewModel), string.Format("UserName={0},Password={1},[{2}]", EllipseState, PWD, result.Message)); 131 MessageBox(result.Message); 132 } 133 #endregion 134 135 136 #region 构造函数 + public PSystemViewModel() 137 public PSystemViewModel() 138 { 139 GlobalVisualizedData.SetMainWindowTitle("系统主页[BigBox777]"); 140 } 141 #endregion 142 143 #region 系统Frame导航 + public void SystemFrameNavigation(FrameworkElement element) 144 public void SystemFrameNavigation(FrameworkElement element) 145 { 146 (UIElement as PSystemView).systemFrame.Navigate(element); 147 } 148 #endregion 149 } 150 }PSystemViewModel.cs
③模块 Demo10A-Models 下添加UserInfo的Login逻辑及返回值LoginResult定义。
1 using Demo10A_Infrastructure.DTO; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace Demo10A_Models 9 { 10 public class LoginResult 11 { 12 public bool Success { get; set; } 13 public string Message { get; set; } 14 public TableUserInfo User { get; set; } 15 } 16 }LoginResult.cs
1 using Demo10A_Infrastructure.DTO; 2 using Demo10A_Infrastructure.Utility; 3 using System; 4 using System.Text.Json; 5 6 namespace Demo10A_Models 7 { 8 public class UserInfo 9 { 10 public static LoginResult Login(string userName,string password) 11 { 12 var tUser= DBHelper.QueryByUsername(userName); 13 if (tUser.Password.Equals(password)) 14 { 15 16 return new LoginResult { Success=true,Message=string.Format("登录成功:{0}", JsonSerializer.Serialize(tUser)),User= tUser }; 17 } 18 return new LoginResult { Success = false, Message = "密码不匹配" }; 19 } 20 } 21 }UserInfo.cs
④模块 Demo10A-Infrastructure 文件夹 DTO 下创建数据库表对象TableUserInfo。
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace Demo10A_Infrastructure.DTO 8 { 9 public class TableUserInfo 10 { 11 public int Id { get; set; } 12 public string UserName { get; set; } 13 public string Password { get; set; } 14 public int Age { get; set; } 15 public decimal Income { get; set; }//收入 16 public string Hobby { get; set; } //爱好 17 } 18 }TableUserInfo.cs
⑤模块 Demo10A-Infrastructure 文件夹 Utility 下创建假数据访问帮助文件DBHelper。
1 using Demo10A_Infrastructure.DTO; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace Demo10A_Infrastructure.Utility 9 { 10 public class DBHelper 11 { 12 private static List<TableUserInfo> userInfos = new List<TableUserInfo>(); 13 static DBHelper() 14 { 15 userInfos.Add(new TableUserInfo { Id = 1, UserName = "BiBo1", Password = "1", Age = 41, Income = 20m, Hobby = "足球" }); 16 userInfos.Add(new TableUserInfo { Id = 1, UserName = "BiBo2", Password = "1", Age = 52, Income = 20m, Hobby = "足球" }); 17 userInfos.Add(new TableUserInfo { Id = 1, UserName = "BiBo3", Password = "1", Age = 26, Income = 20m, Hobby = "足球" }); 18 userInfos.Add(new TableUserInfo { Id = 1, UserName = "BiBo4", Password = "1", Age = 96, Income = 20m, Hobby = "足球" }); 19 userInfos.Add(new TableUserInfo { Id = 1, UserName = "BiBo5", Password = "1", Age = 18, Income = 20m, Hobby = "足球" }); 20 userInfos.Add(new TableUserInfo { Id = 1, UserName = "BiBo6", Password = "1", Age = 60, Income = 20m, Hobby = "足球" }); 21 userInfos.Add(new TableUserInfo { Id = 1, UserName = "BiBo7", Password = "1", Age = 92, Income = 20m, Hobby = "足球" }); 22 userInfos.Add(new TableUserInfo { Id = 1, UserName = "BiBo8", Password = "1", Age = 49, Income = 20m, Hobby = "足球" }); 23 userInfos.Add(new TableUserInfo { Id = 1, UserName = "BiBo9", Password = "1", Age = 22, Income = 20m, Hobby = "足球" }); 24 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Mike1", Password = "1", Age = 77, Income = 20m, Hobby = "足球" }); 25 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Mike2", Password = "1", Age = 10, Income = 20m, Hobby = "足球" }); 26 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Mike3", Password = "1", Age = 27, Income = 20m, Hobby = "足球" }); 27 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Mike4", Password = "1", Age = 29, Income = 20m, Hobby = "足球" }); 28 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Mike5", Password = "1", Age = 81, Income = 20m, Hobby = "足球" }); 29 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Mike6", Password = "1", Age = 90, Income = 20m, Hobby = "足球" }); 30 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Mike7", Password = "1", Age = 98, Income = 20m, Hobby = "足球" }); 31 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Mike8", Password = "1", Age = 42, Income = 20m, Hobby = "足球" }); 32 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Mike9", Password = "1", Age = 40, Income = 20m, Hobby = "足球" }); 33 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Anie1", Password = "1", Age = 48, Income = 20m, Hobby = "足球" }); 34 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Anie2", Password = "1", Age = 74, Income = 20m, Hobby = "足球" }); 35 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Anie3", Password = "1", Age = 69, Income = 20m, Hobby = "足球" }); 36 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Anie4", Password = "1", Age = 82, Income = 20m, Hobby = "足球" }); 37 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Anie5", Password = "1", Age = 85, Income = 20m, Hobby = "足球" }); 38 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Anie6", Password = "1", Age = 40, Income = 20m, Hobby = "足球" }); 39 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Anie7", Password = "1", Age = 59, Income = 20m, Hobby = "足球" }); 40 userInfos.Add(new TableUserInfo { Id = 1, UserName = "BigBox777", Password = "12345", Age = 18, Income = 20m, Hobby = "足球" }); 41 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Anie8", Password = "1", Age = 38, Income = 20m, Hobby = "足球" }); 42 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Anie9", Password = "1", Age = 72, Income = 20m, Hobby = "足球" }); 43 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Tomas1", Password = "1", Age = 75, Income = 20m, Hobby = "足球" }); 44 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Tomas2", Password = "1", Age = 68, Income = 20m, Hobby = "足球" }); 45 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Tomas3", Password = "1", Age = 69, Income = 20m, Hobby = "足球" }); 46 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Tomas4", Password = "1", Age = 73, Income = 20m, Hobby = "足球" }); 47 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Tomas5", Password = "1", Age = 38, Income = 20m, Hobby = "足球" }); 48 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Tomas6", Password = "1", Age = 20, Income = 20m, Hobby = "足球" }); 49 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Tomas7", Password = "1", Age = 28, Income = 20m, Hobby = "足球" }); 50 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Tomas8", Password = "1", Age = 31, Income = 20m, Hobby = "足球" }); 51 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Tomas9", Password = "1", Age = 7, Income = 20m, Hobby = "足球" }); 52 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Anti1", Password = "1", Age = 99, Income = 20m, Hobby = "足球" }); 53 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Anti2", Password = "1", Age = 2, Income = 20m, Hobby = "足球" }); 54 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Anti3", Password = "1", Age = 10, Income = 20m, Hobby = "足球" }); 55 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Anti4", Password = "1", Age = 53, Income = 20m, Hobby = "足球" }); 56 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Anti5", Password = "1", Age = 55, Income = 20m, Hobby = "足球" }); 57 userInfos.Add(new TableUserInfo { Id = 1, UserName = "Anti6", Password = "1", Age = 34, Income = 20m, Hobby = "足球" }); 58 } 59 public static List<TableUserInfo> QueryAllUserInfo() 60 { 61 return userInfos; 62 } 63 public static TableUserInfo QueryByUsername(string userName) 64 { 65 return userInfos.FirstOrDefault<TableUserInfo>(u => u.UserName.Equals(userName)); 66 } 67 } 68 }DBHelper.cs
⑥以上就完成了一个基本的模型业务的使用过程。
3.6、切换可视页面
SPA应用中很多时候需要局部切换可视化区域,我们来做个切换可视化区域的案例。
①模块 Demo10A-Framework 文件夹 ViewModels 下添加数据区域的ViewModel。
1 using Demo10A_Framework.Core; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace Demo10A_Framework.ViewModels 9 { 10 public class PDatagridViewModel:BaseViewModel 11 { 12 } 13 }PDatagridViewModel.cs
②模块 Demo10A-Framework 文件夹 Views 下添加数据区域的View。
1 <Page x:Class="Demo10A_Framework.Views.PDatagridView" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 5 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 6 xmlns:local="clr-namespace:Demo10A_Framework.Views" 7 mc:Ignorable="d" 8 d:DesignHeight="450" d:DesignWidth="800" 9 Title="PDatagridView"> 10 <Grid> 11 12 </Grid> 13 </Page>PDatagridView.xaml
③模块 Demo10A-Framework 文件夹 Views 下更新系统页的View,添加切换页面按钮。
1 <Page x:Class="Demo10A_Framework.Views.PSystemView" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 5 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 6 xmlns:local="clr-namespace:Demo10A_Framework.Views" xmlns:converters="clr-namespace:Demo10A_Framework.Converters" 7 mc:Ignorable="d" 8 d:DesignHeight="450" d:DesignWidth="800" 9 Title="PSystemView"> 10 <Page.Resources> 11 <converters:ConvertChangeState2EllipseFill x:Key="changeStateConvert"/> 12 </Page.Resources> 13 <Grid> 14 <Grid.ColumnDefinitions> 15 <ColumnDefinition Width="250"/> 16 <ColumnDefinition/> 17 </Grid.ColumnDefinitions> 18 <Border Margin="1,0,0,1" Grid.Column="0" BorderThickness="1,1,1,1" BorderBrush="Black"> 19 <StackPanel> 20 <Button Height="30" Content="弹出消息框" Command="{Binding CallMessageBoxCommand}"/> 21 <Border Margin="0" Padding="1,1,1,1" BorderThickness="1,1,1,1" BorderBrush="Red"> 22 <Grid Height="60"> 23 <Grid.ColumnDefinitions> 24 <ColumnDefinition Width="60"/> 25 <ColumnDefinition/> 26 </Grid.ColumnDefinitions> 27 <Grid.RowDefinitions> 28 <RowDefinition/> 29 <RowDefinition/> 30 </Grid.RowDefinitions> 31 <TextBlock Text="窗口标题:" VerticalAlignment="Center"/> 32 <TextBox Text="{Binding SystemTitle}" Grid.Column="1" VerticalAlignment="Center"/> 33 <Button Content="改变窗口标题" Command="{Binding ChangeWindowTitleCommand}" Grid.Row="1" Grid.ColumnSpan="2"/> 34 </Grid> 35 </Border> 36 <Border Margin="0" Padding="1,1,1,1" BorderThickness="1,1,1,1" BorderBrush="Red"> 37 <Grid Height="60"> 38 <Grid.RowDefinitions> 39 <RowDefinition/> 40 <RowDefinition/> 41 </Grid.RowDefinitions> 42 <StackPanel Grid.Column="1" VerticalAlignment="Center" Orientation="Horizontal"> 43 <Ellipse Width="28" Height="28" Fill="{Binding EllipseState,Converter={StaticResource changeStateConvert}}" Margin="0,0,5,0"/> 44 <Ellipse Width="28" Height="28" Fill="{Binding EllipseState,Converter={StaticResource changeStateConvert}}" Margin="0,0,5,0"/> 45 <Ellipse Width="28" Height="28" Fill="{Binding EllipseState,Converter={StaticResource changeStateConvert},ConverterParameter='1'}" Margin="0,0,5,0"/> 46 <Ellipse Width="28" Height="28" Fill="{Binding EllipseState,Converter={StaticResource changeStateConvert},ConverterParameter='1'}" Margin="0,0,5,0"/> 47 <Ellipse Width="28" Height="28" Fill="{Binding EllipseState,Converter={StaticResource changeStateConvert},ConverterParameter='2'}" Margin="0,0,5,0"/> 48 <Ellipse Width="28" Height="28" Fill="{Binding EllipseState,Converter={StaticResource changeStateConvert},ConverterParameter='2'}" Margin="0,0,5,0"/> 49 </StackPanel> 50 <Button Content="转换器使用" Command="{Binding UseConverterCommand}" Grid.Row="1" Grid.ColumnSpan="2"/> 51 </Grid> 52 </Border> 53 <Button Height="30" Content="创建新窗口"/> 54 <Button Height="30" Content="关闭新窗口"/> 55 <Border Margin="0" Padding="1,1,1,1" BorderThickness="1,1,1,1" BorderBrush="Red"> 56 <Grid Height="80"> 57 <Grid.ColumnDefinitions> 58 <ColumnDefinition Width="60"/> 59 <ColumnDefinition/> 60 </Grid.ColumnDefinitions> 61 <Grid.RowDefinitions> 62 <RowDefinition/> 63 <RowDefinition/> 64 <RowDefinition/> 65 </Grid.RowDefinitions> 66 <TextBlock Text="用户名:" VerticalAlignment="Center"/> 67 <TextBox Text="{Binding UserName}" Grid.Column="1" VerticalAlignment="Center"/> 68 <TextBlock Text="密码:" Grid.Row="1" VerticalAlignment="Center"/> 69 <TextBox Text="{Binding PWD}" Grid.Row="1" Grid.Column="1" VerticalAlignment="Center"/> 70 <Button Content="登录" Command="{Binding LoginCommand}" Grid.Row="2" Grid.ColumnSpan="2"/> 71 </Grid> 72 </Border> 73 <Button Height="30" Content="切换页面" Command="{Binding CreateDataPageCommand}"/> 74 <Button Height="30" Content="查询结果分页显示" Command="{Binding QueryPaginationCommand}"/> 75 </StackPanel> 76 </Border> 77 <Frame x:Name="systemFrame" Grid.Column="1"> 78 <Frame.Background> 79 <VisualBrush Stretch="Uniform" Opacity="0.5" Viewbox="-1,-1,3,3"> 80 <VisualBrush.Visual> 81 <TextBlock Text="BigBox777"/> 82 </VisualBrush.Visual> 83 </VisualBrush> 84 </Frame.Background> 85 </Frame> 86 </Grid> 87 </Page>PSystemView.xaml
④模块 Demo10A-Framework 文件夹 ViewModels 下更新系统页的ViewModel,添加切换命令。
1 using Demo10A_Framework.Core; 2 using Demo10A_Framework.Globals; 3 using Demo10A_Framework.Views; 4 using Demo10A_Models; 5 using System; 6 using System.Collections.Generic; 7 using System.Linq; 8 using System.Text; 9 using System.Threading.Tasks; 10 using System.Windows; 11 using System.Windows.Controls; 12 13 namespace Demo10A_Framework.ViewModels 14 { 15 public class PSystemViewModel:BaseViewModel 16 { 17 #region 事件-消息框 + public DelegateCommand CallMessageBoxCommand 18 public DelegateCommand CallMessageBoxCommand 19 { 20 get 21 { 22 return new DelegateCommand(CallMessageBoxCommand_Executed); 23 } 24 } 25 26 private void CallMessageBoxCommand_Executed(object obj) 27 { 28 GlobalVisualizedData.WriteLog(typeof(PSystemViewModel), string.Format("创建消息提示框,消息标题:{0},消息:{1}", "防诈提醒", "快捷支付多份心,莫名中奖少顿惜。 网购陷阱花样多,线上交易要当心。")); 29 MessageBox("快捷支付多份心,莫名中奖少顿惜。 网购陷阱花样多,线上交易要当心。", "防诈提醒"); 30 } 31 #endregion 32 33 #region 属性-系统标题 + public string SystemTitle 34 private string _systemTitle = "系统主页[BigBox777]"; 35 public string SystemTitle 36 { 37 get { return _systemTitle; } 38 set 39 { 40 _systemTitle = value; 41 RaisePropertyChanged(); 42 } 43 } 44 #endregion 45 46 #region 事件-更改标题 + public DelegateCommand ChangeWindowTitleCommand 47 public DelegateCommand ChangeWindowTitleCommand 48 { 49 get 50 { 51 return new DelegateCommand(ChangeWindowTitleCommand_Executed); 52 } 53 } 54 55 private void ChangeWindowTitleCommand_Executed(object obj) 56 { 57 GlobalVisualizedData.WriteLog(typeof(PSystemViewModel), string.Format("更改主窗口标题,SystemTitle={0}", SystemTitle)); 58 GlobalVisualizedData.SetMainWindowTitle(SystemTitle); 59 } 60 #endregion 61 62 #region 属性-圆状态 + public bool EllipseState 63 private bool _ellipseState; 64 65 public bool EllipseState 66 { 67 get { return _ellipseState; } 68 set 69 { 70 _ellipseState = value; 71 RaisePropertyChanged(); 72 } 73 } 74 #endregion 75 76 #region 事件-转换器使用 + public DelegateCommand UseConverterCommand 77 public DelegateCommand UseConverterCommand 78 { 79 get 80 { 81 return new DelegateCommand(UseConverterCommand_Executed); 82 } 83 } 84 85 private void UseConverterCommand_Executed(object obj) 86 { 87 GlobalVisualizedData.WriteLog(typeof(PSystemViewModel), string.Format("使用转换器更改圆状态,EllipseState={0}", EllipseState)); 88 EllipseState = !EllipseState; 89 } 90 #endregion 91 92 #region 属性-用户名 + public string UserName 93 private string _userName = "BigBox777"; 94 public string UserName 95 { 96 get { return _userName; } 97 set 98 { 99 _userName = value; 100 RaisePropertyChanged(); 101 } 102 } 103 #endregion 104 105 #region 属性-密码 + public string PWD 106 private string _PWD = "12345"; 107 public string PWD 108 { 109 get { return _PWD; } 110 set 111 { 112 _PWD = value; 113 RaisePropertyChanged(); 114 } 115 } 116 #endregion 117 118 #region 事件-登录 + public DelegateCommand LoginCommand 119 public DelegateCommand LoginCommand 120 { 121 get 122 { 123 return new DelegateCommand(LoginCommand_Executed); 124 } 125 } 126 127 private void LoginCommand_Executed(object obj) 128 { 129 UserInfo userInfo = new UserInfo(); 130 var result = userInfo.Login(UserName,PWD); 131 GlobalVisualizedData.WriteLog(typeof(PSystemViewModel), string.Format("UserName={0},Password={1},[{2}]", EllipseState, PWD, result.Message)); 132 MessageBox(result.Message); 133 } 134 #endregion 135 136 #region 事件-切换页 + public DelegateCommand CreateDataPageCommand 137 public DelegateCommand CreateDataPageCommand 138 { 139 get 140 { 141 return new DelegateCommand(CreateDataPageCommand_Executed); 142 } 143 } 144 145 private void CreateDataPageCommand_Executed(object obj) 146 { 147 var frame = (UIElement as PSystemView).systemFrame; 148 if (frame.Content is PLoggerView) 149 { 150 (UIElement as PSystemView).systemFrame.Navigate(datagridViewModel.UIElement); 151 } 152 else 153 { 154 (UIElement as PSystemView).systemFrame.Navigate(loggerViewModel.UIElement); 155 } 156 } 157 #endregion 158 159 160 internal PLoggerViewModel loggerViewModel; //Logger页ViewModel 161 internal PDatagridViewModel datagridViewModel; //Datagrid页ViewModel 162 163 #region 构造函数 + public PSystemViewModel() 164 public PSystemViewModel() 165 { 166 loggerViewModel = new PLoggerViewModel(); 167 datagridViewModel = new PDatagridViewModel(); 168 (UIElement as PSystemView).systemFrame.Navigate(loggerViewModel.UIElement); 169 } 170 #endregion 171 } 172 }PSystemViewModel.cs
⑤以上就完成了可视化区域的切换,右侧区域可以在日志显示和数据显示间来回切换。
3.7、查询数据分页显示
常见查询回来的数据集合都非常的大,这节我们来做个分页显示的案例。
①模块 Demo10A-Framework 文件夹 ViewModels 下更新数据区域的ViewModel。
1 using Demo10A_Framework.Core; 2 using Demo10A_Framework.Globals; 3 using Demo10A_Infrastructure.DTO; 4 using Demo10A_Models; 5 using System; 6 using System.Collections.Generic; 7 using System.Collections.ObjectModel; 8 using System.Linq; 9 using System.Text; 10 using System.Threading.Tasks; 11 using System.Windows.Controls; 12 13 namespace Demo10A_Framework.ViewModels 14 { 15 public class PDataViewModel:BaseViewModel 16 { 17 private DataManager<TableUserInfo> _users; 18 public DataManager<TableUserInfo> Users 19 { 20 get { return _users; } 21 set { _users = value; RaisePropertyChanged(); } 22 } 23 public DelegateCommand ControlButtonCommand 24 { 25 get 26 { 27 return new DelegateCommand(ControlButtonCommand_Executed); 28 } 29 } 30 private void ControlButtonCommand_Executed(object obj) 31 { 32 if(obj is string) 33 { 34 EnumControlButton cb = Enum.Parse<EnumControlButton>(obj as string); 35 switch (cb) 36 { 37 case EnumControlButton.NavHome: 38 _users.NavHome(); 39 break; 40 case EnumControlButton.NavPrevious: 41 _users.NavPrevious(); 42 break; 43 case EnumControlButton.NavFirst: 44 _users.NavFirst(); 45 break; 46 case EnumControlButton.NavSecond: 47 _users.NavSecond(); 48 break; 49 case EnumControlButton.NavThird: 50 _users.NavThird(); 51 break; 52 case EnumControlButton.NavFourth: 53 _users.NavFourth(); 54 break; 55 case EnumControlButton.NavFifth: 56 _users.NavFifth(); 57 break; 58 case EnumControlButton.NavNext: 59 _users.NavNext(); 60 break; 61 case EnumControlButton.NavEnd: 62 _users.NavEnd(); 63 break; 64 default: 65 break; 66 } 67 } 68 } 69 70 public PDataViewModel() 71 { 72 var user = new UserInfo(); 73 _users = new DataManager<TableUserInfo>(user.QueryAllUserInfo()); 74 } 75 } 76 }PDataViewModel.cs
②模块 Demo10A-Framework 文件夹 Views 下更新数据区域的View。
1 <Page x:Class="Demo10A_Framework.Views.PDataView" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 5 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 6 xmlns:local="clr-namespace:Demo10A_Framework.Views" xmlns:converters="clr-namespace:Demo10A_Framework.Converters" 7 mc:Ignorable="d" 8 d:DesignHeight="450" d:DesignWidth="800" 9 Title="PDataView"> 10 <Page.Resources> 11 <converters:ConvertBool2Visibility x:Key="visibilityConvert"/> 12 </Page.Resources> 13 <Grid> 14 <Grid.RowDefinitions> 15 <RowDefinition/> 16 <RowDefinition Height="30"/> 17 </Grid.RowDefinitions> 18 <DataGrid ItemsSource="{Binding Users.ItemSource}" SelectedItem="{Binding Users.SelectedItem}"/> 19 <StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Center"> 20 <Button Content="{Binding Users.NavHomeContent}" Visibility="{Binding Users.NavHomeVisibility,Converter={StaticResource visibilityConvert}}" Width="40" Command="{Binding ControlButtonCommand}" CommandParameter="NavHome"/> 21 <Button Content="{Binding Users.NavPreviousContent}" Visibility="{Binding Users.NavPreviousVisibility,Converter={StaticResource visibilityConvert}}" Width="40" Command="{Binding ControlButtonCommand}" CommandParameter="NavPrevious"/> 22 <Button Content="{Binding Users.NavFirstContent}" Visibility="{Binding Users.NavFirstVisibility,Converter={StaticResource visibilityConvert}}" Width="40" Command="{Binding ControlButtonCommand}" CommandParameter="NavFirst"/> 23 <Button Content="{Binding Users.NavSecondContent}" Visibility="{Binding Users.NavSecondVisibility,Converter={StaticResource visibilityConvert}}" Width="40" Command="{Binding ControlButtonCommand}" CommandParameter="NavSecond"/> 24 <Button Content="{Binding Users.NavThirdContent}" Visibility="{Binding Users.NavThirdVisibility,Converter={StaticResource visibilityConvert}}" Width="40" Command="{Binding ControlButtonCommand}" CommandParameter="NavThird"/> 25 <Button Content="{Binding Users.NavFourthContent}" Visibility="{Binding Users.NavFourthVisibility,Converter={StaticResource visibilityConvert}}" Width="40" Command="{Binding ControlButtonCommand}" CommandParameter="NavFourth"/> 26 <Button Content="{Binding Users.NavFifthContent}" Visibility="{Binding Users.NavFifthVisibility,Converter={StaticResource visibilityConvert}}" Width="40" Command="{Binding ControlButtonCommand}" CommandParameter="NavFifth"/> 27 <Button Content="{Binding Users.NavNextContent}" Visibility="{Binding Users.NavNextVisibility,Converter={StaticResource visibilityConvert}}" Width="40" Command="{Binding ControlButtonCommand}" CommandParameter="NavNext"/> 28 <Button Content="{Binding Users.NavEndContent}" Visibility="{Binding Users.NavEndVisibility,Converter={StaticResource visibilityConvert}}" Width="40" Command="{Binding ControlButtonCommand}" CommandParameter="NavEnd"/> 29 </StackPanel> 30 </Grid> 31 </Page>PDataView.xaml
③模块 Demo10A-Framework 文件夹 Globals 下添加数据分页管理类DataManager.cs。
1 using Demo10A_Framework.Core; 2 using System; 3 using System.Collections.Generic; 4 using System.Collections.ObjectModel; 5 using System.Linq; 6 using System.Text; 7 using System.Threading.Tasks; 8 9 namespace Demo10A_Framework.Globals 10 { 11 public class DataManager<T>: NotificationObject 12 { 13 private ObservableCollection<T> _itemSource; 14 public ObservableCollection<T> ItemSource { get { return _itemSource; } set { _itemSource = value; RaisePropertyChanged(); } } 15 public T SelectedItem { get; set; } 16 17 #region 绑定控制按钮属性 18 private EnumControlButton _controlButton; 19 public EnumControlButton ControlButton 20 { 21 get { return _controlButton; } 22 set { _controlButton = value; RaisePropertyChanged(); } 23 } 24 25 private string _navHomeContent = "首页"; 26 public string NavHomeContent { get { return _navHomeContent; } set { _navHomeContent = value; RaisePropertyChanged(); } } 27 private bool _navHomeVisibility; 28 public bool NavHomeVisibility { get { return _navHomeVisibility; } set { _navHomeVisibility = value; RaisePropertyChanged(); } } 29 private string _navPreviousContent = "上一页"; 30 public string NavPreviousContent { get { return _navPreviousContent; } set { _navPreviousContent = value; RaisePropertyChanged(); } } 31 private bool _navPreviousVisibility; 32 public bool NavPreviousVisibility { get { return _navPreviousVisibility; } set { _navPreviousVisibility = value; RaisePropertyChanged(); } } 33 private int _navFirstContent = 1; 34 public int NavFirstContent { get { return _navFirstContent; } set { _navFirstContent = value; RaisePropertyChanged(); } } 35 private bool _navFirstVisibility; 36 public bool NavFirstVisibility { get { return _navFirstVisibility; } set { _navFirstVisibility = value; RaisePropertyChanged(); } } 37 private int _navSecondContent = 2; 38 public int NavSecondContent { get { return _navSecondContent; } set { _navSecondContent = value; RaisePropertyChanged(); } } 39 private bool _navSecondVisibility; 40 public bool NavSecondVisibility { get { return _navSecondVisibility; } set { _navSecondVisibility = value; RaisePropertyChanged(); } } 41 private int _navThirdContent = 3; 42 public int NavThirdContent { get { return _navThirdContent; } set { _navThirdContent = value; RaisePropertyChanged(); } } 43 private bool _navThirdVisibility; 44 public bool NavThirdVisibility { get { return _navThirdVisibility; } set { _navThirdVisibility = value; RaisePropertyChanged(); } } 45 private int _navFourthContent = 4; 46 public int NavFourthContent { get { return _navFourthContent; } set { _navFourthContent = value; RaisePropertyChanged(); } } 47 private bool _navFourthVisibility; 48 public bool NavFourthVisibility { get { return _navFourthVisibility; } set { _navFourthVisibility = value; RaisePropertyChanged(); } } 49 private int _navFifthContent = 5; 50 public int NavFifthContent { get { return _navFifthContent; } set { _navFifthContent = value; RaisePropertyChanged(); } } 51 private bool _navFifthVisibility; 52 public bool NavFifthVisibility { get { return _navFifthVisibility; } set { _navFifthVisibility = value; RaisePropertyChanged(); } } 53 private string _navNextContent = "下一页"; 54 public string NavNextContent { get { return _navNextContent; } set { _navNextContent = value; RaisePropertyChanged(); } } 55 private bool _navNextVisibility; 56 public bool NavNextVisibility { get { return _navNextVisibility; } set { _navNextVisibility = value; RaisePropertyChanged(); } } 57 private string _navEndContent = "尾页"; 58 public string NavEndContent { get { return _navEndContent; } set { _navEndContent = value; RaisePropertyChanged(); } } 59 private bool _navEndVisibility; 60 public bool NavEndVisibility { get { return _navEndVisibility; } set { _navEndVisibility = value; RaisePropertyChanged(); } } 61 #endregion 62 63 public void NavHome() 64 { 65 if (_currentPageNumber >= 1) 66 { 67 ShowPage(1); 68 } 69 } 70 public void NavPrevious() 71 { 72 if (_currentPageNumber > 1) 73 { 74 ShowPage(_currentPageNumber - 1); 75 } 76 } 77 public void NavFirst() 78 { 79 ShowPage(NavFirstContent); 80 } 81 public void NavSecond() 82 { 83 ShowPage(NavSecondContent); 84 } 85 public void NavThird() 86 { 87 ShowPage(NavThirdContent); 88 } 89 public void NavFourth() 90 { 91 ShowPage(NavFourthContent); 92 } 93 public void NavFifth() 94 { 95 ShowPage(NavFifthContent); 96 } 97 public void NavNext() 98 { 99 if (_currentPageNumber < _maxPageNumber) 100 { 101 ShowPage(_currentPageNumber + 1); 102 } 103 } 104 public void NavEnd() 105 { 106 if (_maxPageNumber >= 1) 107 { 108 ShowPage(_maxPageNumber); 109 } 110 } 111 112 113 private List<T> _dataSource; 114 private int _pageCount = 8; 115 private int _currentPageNumber = 1; 116 private int _maxPageNumber; 117 118 public DataManager(List<T> data) 119 { 120 _dataSource = data; 121 //初始化显示 122 //1、计算最大页数 123 _maxPageNumber = (int)Math.Ceiling(_dataSource.Count * 1.0 / _pageCount); 124 if (_maxPageNumber == 1) 125 { 126 NavFirstVisibility = true; 127 } 128 else if (_maxPageNumber > 1) 129 { 130 NavHomeVisibility = true; 131 NavPreviousVisibility = true; 132 NavNextVisibility = true; 133 NavEndVisibility = true; 134 if (_maxPageNumber > 1) 135 { 136 NavFirstVisibility = true; 137 NavSecondVisibility = true; 138 } 139 if (_maxPageNumber > 2) 140 { 141 NavThirdVisibility = true; 142 } 143 if (_maxPageNumber > 3) 144 { 145 NavFourthVisibility = true; 146 } 147 if (_maxPageNumber > 4) 148 { 149 NavFifthVisibility = true; 150 } 151 } 152 ShowPage(1); 153 } 154 private void ShowPage(int pageNumber) 155 { 156 //更新数据 157 _currentPageNumber = pageNumber; 158 ItemSource = new ObservableCollection<T>(_dataSource.Skip(_pageCount * (pageNumber - 1)).Take(_pageCount)); 159 160 //更新按钮 161 if(pageNumber != _navThirdContent) 162 { 163 if(pageNumber==_navFirstContent) 164 { 165 if (_navFirstContent > 2) 166 { 167 UpdateShowPageNumber(-2); 168 } 169 else if (_navFirstContent > 1) 170 { 171 UpdateShowPageNumber(-1); 172 } 173 } 174 else if(pageNumber == _navSecondContent) 175 { 176 if (_navFirstContent > 1) 177 { 178 UpdateShowPageNumber(-1); 179 } 180 } 181 else if(pageNumber == _navFifthContent) 182 { 183 if (_maxPageNumber - _navFifthContent >= 2) 184 { 185 UpdateShowPageNumber(2); 186 } 187 else if (_maxPageNumber - _navFifthContent >= 1) 188 { 189 UpdateShowPageNumber(1); 190 } 191 } 192 else if(pageNumber == _navFourthContent) 193 { 194 if (_maxPageNumber - _navFifthContent >= 1) 195 { 196 UpdateShowPageNumber(1); 197 } 198 } 199 else 200 { 201 if (pageNumber - _navFifthContent >= 2) 202 { 203 UpdateShowPageNumber(2); 204 } 205 else if (pageNumber - _navFifthContent >= 1) 206 { 207 UpdateShowPageNumber(1); 208 } 209 else if (_navFirstContent - pageNumber >= 2) 210 { 211 UpdateShowPageNumber(-2); 212 } 213 else if (_navFirstContent - pageNumber >= 1) 214 { 215 UpdateShowPageNumber(-1); 216 } 217 } 218 } 219 220 } 221 private void UpdateShowPageNumber(int count) 222 { 223 NavFirstContent = NavFirstContent + count; 224 NavSecondContent = NavSecondContent + count; 225 NavThirdContent = NavThirdContent + count; 226 NavFourthContent = NavFourthContent + count; 227 NavFifthContent = NavFifthContent + count; 228 } 229 230 231 } 232 233 public enum EnumControlButton 234 { 235 NavHome, 236 NavPrevious, 237 NavFirst, 238 NavSecond, 239 NavThird, 240 NavFourth, 241 NavFifth, 242 NavNext, 243 NavEnd 244 } 245 }DataManager.cs
④模块 Demo10A-Models 更新用户信息业务UserInfo.cs。
1 using Demo10A_Infrastructure.DTO; 2 using Demo10A_Infrastructure.Utility; 3 using System; 4 using System.Collections.Generic; 5 using System.Text.Json; 6 7 namespace Demo10A_Models 8 { 9 public class UserInfo 10 { 11 public string UserName { get; set; } 12 public string Password { get; set; } 13 public LoginResult Login() 14 { 15 var tUser= DBHelper.QueryByUsername(UserName); 16 if (tUser.Password.Equals(Password)) 17 { 18 19 return new LoginResult { Success=true,Message=string.Format("登录成功:{0}", JsonSerializer.Serialize(tUser)),User= tUser }; 20 } 21 return new LoginResult { Success = false, Message = "密码不匹配" }; 22 } 23 public List<TableUserInfo> QueryAllUserInfo() 24 { 25 return DBHelper.QueryAllUserInfo(); 26 } 27 } 28 }UserInfo.cs
⑤以上就完成了数据分页显示的功能。
4、框架使用
稍后补充
5、参考
kiba518的博客 https://www.cnblogs.com/kiba/category/1291917.html