WPF框架简介
虽然WPF只是作为一个盒子/容器使用,但是WPF我还是用上了Prism框架,来实现WPF项目的MVVM架构思想
初次使用Prism,需要有一定的WPF开发经验,话不多说,开始吧
App.xaml的修改
- wpf的程序入口是从app.xaml开始的,开始对其进行修改
将prism根节点代替原来的app节点,同时增加xmls:prism节点、xmls:hc- xml:hc是HandyControl前端UI控件,不用可以不用添加
- xmls:prism 是关键的Prism节点
- 去除了 StartUri 默认启动页面,改为在App.xaml.cs启动页面
<prism:PrismApplication x:Class="WPF.NetCore.Startup.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WPF.NetCore.Startup"
xmlns:prism="http://prismlibrary.com/"
xmlns:hc="https://handyorg.github.io/handycontrol" >
<Application.Resources>
</Application.Resources>
</prism:PrismApplication>
App.xaml.cs的修改
主要修改了几个地方
- 修改app.xaml.cs集成的Application 变成了 PrismApplication
- 去继承实现 CreateShell(),注册TextEncoding(好像是解决中文乱码的问题…记不清了)
- 打开首界面,首界面为 MainWindow
- RegisterTypes() 注册Prism页面,我用了反射去写,到时候大家可以去看源码 (如果只是简单的几个页面,也可以直接手工注册)
- ConfigureViewModelLocator() 修改Prism viewmodel文件的映射名,比如 wpf.netcore.startup.xaml,修改后就prism框架就会去寻找wpf.netcore.startupVM.xaml
using Prism.Ioc;
using Prism.Mvvm;
using Prism.Unity;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows;
namespace WPF.NetCore.Startup
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : PrismApplication
{
//初始化创建
protected override Window CreateShell()
{
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
return Container.Resolve<WPF.NetCore.Startup.MainWindow>();
}
#region 重写Prism框架部分方法
#region 重写ViewModel的命名方法
/// <summary>
/// 重写ViewModel的命名方法,修改默认名称为 xxxVM.cs
/// </summary>
protected override void ConfigureViewModelLocator()
{
base.ConfigureViewModelLocator();
ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver((viewType) =>
{
var viewName = viewType.FullName.Replace(".ViewModels.", ".CustomNamespace.");
var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName;
var viewModelName = $"{viewName}VM, {viewAssemblyName}";
return Type.GetType(viewModelName);
});
}
#endregion
/// <summary>
/// prism页面注册
/// </summary>
/// <param name="containerRegistry"></param>
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
//页面注册
WPF.NetCore.PrismCore.RegisterTools.RegisterPrismInit(containerRegistry);
}
#endregion
}
}
首界面代码修改 MainWindow
首界面中修改了如下(都是prism框架的基本规则):
- 增加xmlns:prism=“http://prismlibrary.com/”(prism框架引用)
- prism:ViewModelLocator.AutoWireViewModel=“True”(使用vm文件)
- xmlns:b=“http://schemas.microsoft.com/xaml/behaviors”(事件触发)
- 增加了对应的Loaded(初始化加载事件)
- 在内容中,增加了ContentControl这个组件,用于放置Prism的内容容器
<Window x:Class="WPF.NetCore.Startup.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPF.NetCore.Startup.Control"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
>
<b:Interaction.Triggers>
<b:EventTrigger EventName="Loaded">
<b:InvokeCommandAction Command="{Binding Loaded}" />
</b:EventTrigger>
</b:Interaction.Triggers>
<Grid>
<ContentControl prism:RegionManager.RegionName="FrameView" x:Name="FrameView" />
</Grid>
</Window>
对应的cs文件
添加了Region容器注册,不知道朋友可以去看下相关的
using Prism.Regions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using WPF.NetCore.Public.PublicConst;
namespace WPF.NetCore.Startup
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
RegionManager.SetRegionName(this.FrameView, RegionConst.FrameView);
}
}
}
MainWindowVM文件
添加了load方法,并实现,跳转了一个页面 MainBrowser(UserControl类型)
using Prism.Commands;
using Prism.Ioc;
using Prism.Regions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using WPF.NetCore.PrismCore.Model;
using WPF.NetCore.Public.PublicConst;
using WPF.NetCore.Startup.Control;
namespace WPF.NetCore.Startup
{
public class MainWindowVM : BasicVM
{
public MainWindowVM(IContainerExtension container) : base(container)
{
}
public DelegateCommand Loaded => new DelegateCommand(async () => await Load());
/// <summary>
/// 页面加载
/// </summary>
/// <returns></returns>
async Task Load()
{
IRegion region = RegionManager.Regions[RegionConst.FrameView];
region.RequestNavigate("WPF.NetCore.Startup.Control.MainBrowser");
}
}
}
PS:注册及反射相关代码
using Prism.Ioc;
using Prism.Modularity;
using Prism.Regions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using WPF.NetCore.Common;
namespace WPF.NetCore.PrismCore
{
/// <summary>
/// 注册帮助类
/// </summary>
public class RegisterTools
{
/// <summary>
/// 初始化 注册方法
/// </summary>
/// <param name="containerRegistry"></param>
public static void RegisterPrismInit(IContainerRegistry containerRegistry)
{
//将所有的UserControl注册到Region中
//注册所有的Page,windows和control
RegisterPrism<Page>(containerRegistry);
RegisterPrism<Window>(containerRegistry);
RegisterPrism<UserControl>(containerRegistry);
}
/// <summary>
/// 初始化 注册方法
/// </summary>
/// <param name="containerRegistry"></param>
public static void RegisterPrismModule(IModuleCatalog moduleCatalog)
{
//注册系统模块
//RegisterPrism<IModule>(moduleCatalog);
}
/// <summary>
/// 各类型组件注册
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="containerRegistry"></param>
private static void RegisterPrism<T>(IContainerRegistry containerRegistry)
{
var ass = DllTools.FindAssemblies();
if (ass != null)
{
var result = ass.SelectMany(t => t.GetTypes()).Where(i => i.IsSubclassOf(typeof(T)));
foreach (var type in result)
{
containerRegistry.RegisterForNavigation(type, type.FullName);
}
}
}
/// <summary>
/// 各类型组件注册
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="containerRegistry"></param>
private static void RegisterPrism<T>(IModuleCatalog moduleCatalog)
{
var ass = DllTools.FindAssemblies();
if (ass != null)
{
var result = ass.SelectMany(t => t.GetTypes()).Where(i => i.IsSubclassOf(typeof(T)));
foreach (var type in result)
{
moduleCatalog.AddModule(new ModuleInfo
{
ModuleName = type.Name,
ModuleType = type.AssemblyQualifiedName,
InitializationMode = InitializationMode.OnDemand
});
}
}
}
/// <summary>
/// 为主窗口注册所有的UserControl
/// </summary>
/// <param name="regionName"></param>
public static void RegisterUserControlToRegion(IRegionBehaviorFactory containerRegistry, string regionName)
{
var ass = DllTools.FindAssemblies();
if (ass != null)
{
var result = ass.SelectMany(t => t.GetTypes()).Where(i => i.IsSubclassOf(typeof(UserControl)));
foreach (var type in result)
{
containerRegistry.AddIfMissing(regionName, type);
}
}
}
}
}
通过反射来取项目里面的所有的dll
using Microsoft.Extensions.DependencyModel;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace WPF.NetCore.Common
{
/// <summary>
/// Dll模块帮助类
/// </summary>
public class DllTools
{
/// <summary>
/// 获取本地目录下的所有dll
/// </summary>
/// <returns></returns>
public static List<Assembly> GetAssemblies()
{
var referenceAssemblies = new List<Assembly>();
string[] assemblyNames = DependencyContext.Default.GetDefaultAssemblyNames().Select(p => p.Name).ToArray();
assemblyNames = GetFilterAssemblies(assemblyNames).Distinct().ToArray();
foreach (var name in assemblyNames)
{
referenceAssemblies.Add(Assembly.Load(name));
}
return referenceAssemblies;
}
/// <summary>
/// 获取所有的dll组件
/// </summary>
/// <returns></returns>
public static Assembly[] FindAssemblies()
{
string[] filters =
{
"mscorlib",
"netstandard",
"dotnet",
"api-ms-win-core",
"runtime.",
"System",
"Microsoft",
"Window",
};
DependencyContext context = DependencyContext.Default;
if (context != null)
{
List<string> names = new List<string>();
string[] dllNames = context.CompileLibraries.SelectMany(m => m.Assemblies).Distinct().Select(m => m.Replace(".dll", ""))
.OrderBy(m => m).ToArray();
if (dllNames.Length > 0)
{
names = (from name in dllNames
let i = name.LastIndexOf('/') + 1
select name.Substring(i, name.Length - i)).Distinct()
.Where(name => !filters.Any(name.StartsWith))
.OrderBy(m => m).ToList();
}
else
{
foreach (CompilationLibrary library in context.CompileLibraries)
{
string name = library.Name;
if (name == "KWT") continue;
if (!names.Contains(name))
{
names.Add(name);
}
}
}
return LoadFiles(names);
}
//遍历文件夹的方式,用于传统.netfx
string path = Directory.GetCurrentDirectory();
string[] files = Directory.GetFiles(path, "*.dll", SearchOption.TopDirectoryOnly)
.Concat(Directory.GetFiles(path, "*.exe", SearchOption.TopDirectoryOnly))
.ToArray();
return files.Where(file => filters.All(token => Path.GetFileName(file)?.StartsWith(token) != true)).Select(Assembly.LoadFrom).ToArray();
}
/// <summary>
/// Dll文件过滤
/// </summary>
/// <param name="assemblyNames"></param>
/// <returns></returns>
private static string[] GetFilterAssemblies(string[] assemblyNames)
{
//var relatedFile = "WPF.Net";
var pattern = "^Microsoft.\\w*|^System.\\w*|^runtime.\\w*|^Newtonsoft.Json.\\w*";
Regex notRelatedRegex = new Regex(pattern, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase);
return
assemblyNames.Where(
name => !notRelatedRegex.IsMatch(name)).ToArray();
}
private static Assembly[] LoadFiles(IEnumerable<string> files)
{
List<Assembly> assemblies = new List<Assembly>();
foreach (string file in files)
{
AssemblyName name = new AssemblyName(file);
try
{
assemblies.Add(Assembly.Load(name));
}
catch (FileNotFoundException)
{ }
}
return assemblies.ToArray();
}
}
}