Prism.Unity
Prism.Wpf
首先简单的说一下 MVVM 是一种数据驱动试图的模式 通过修改数据来触发界面上的变化,Prism.Unity 是一个IOC 容器框架
// 首先继承 PrismApplication
public partial class App : PrismApplication{
// 主界面
protected override Window CreateShell()
{
return Container.Resolve<MainWindow>;
}
// 初始化前的判断
protected override void InitializeShell(Window shell)
{
if (Container.Resolve<Login>().ShowDialog() == false)
{
Application.Current?.Shutdown();
}
else
{
base.InitializeShell(shell);
}
}
// 容器注册服务的地方
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.Register<ILoginService, LoginService>();
containerRegistry.RegisterScoped<DBContext>();
}
}
<Window x:Class="NhxProjectSystem.Main.Views.Login"
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:NhxProjectSystem.Main.Views"
mc:Ignorable="d"
Name="loginWindow"
WindowStartupLocation="CenterScreen"
Title="登录" MaxHeight="450" MaxWidth="700" MinWidth="700" MinHeight="450"
ResizeMode="NoResize "
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
>
<Grid >
<DockPanel>
<Image Grid.Column="0" Source="/Image/LoginBg.png" Height="450" Width="400" />
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" >
<TextBlock Width="280" TextAlignment="Center" Padding="0,30,0,30" FontSize="27" LineHeight="30" >系统TextBlock>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" >
<TextBlock Width="260" >账号TextBlock>
<TextBox TextWrapping="Wrap" Text="{Binding UserName,Mode=TwoWay}" Name="UserName" Padding="0,5" Margin="0,0,0,20" BorderBrush="#40a9ff" />
<TextBlock >密码TextBlock>
<TextBox TextWrapping="Wrap" Text="{Binding Password,Mode=TwoWay}" Name="Password" Padding="0,5" Margin="0,0,0,20" />
<Button Content="登 录" Padding="0,5" CommandParameter="{Binding ElementName=loginWindow}" Command="{Binding LoginCommand}" />
StackPanel>
StackPanel>
DockPanel>
Grid>
Window>
public interface ILoginService
{
User UserLogin(string username, string password);
}
public class LoginService : ILoginService
{
[Dependency] // using Unity;
public DBContext _DBContext { get; set; }
public User UserLogin(string username, string password)
{
return _DBContext .NhxUsers.AsNoTracking().FirstOrDefault(c=>c.Password==password&&c.Account==username);
}
}
public class LoginViewModel : BindableBase
{
[Dependency] //属性注入;
public ILoginService _loginService { get; set; }
private string userName = "";
private string password = "";
public string UserName
{
get { return userName; }
set { SetProperty(ref userName, value); }
}
public string Password
{
get { return password; }
set { SetProperty(ref password, value); }
}
// 命令
ICommand? loginCommand;
public ICommand LoginCommand
{
get
{
if (loginCommand == null)
{
loginCommand = new DelegateCommand<object>(UserLogin);
}
return loginCommand;
}
}
void UserLogin(object obj)
{
var LoginUser=_loginService.UserLogin(this.UserName, this.Password);
if (LoginUser == null)
{
MessageBox.Show("用户名或密码错误");
return;
}
(obj as Window).DialogResult = true;
}
}
}
原本是准备按照正常的方式来实现 但是看了一些文章和实现方式发现了一种更好的更解耦的方式 中间踩了很多坑 记录一下
这是我的布局图 看似很简单 我当初实现的时候也是这样想的
现在要考虑三个问题 1 动态菜单 2 工具栏事件的消息订阅 我在每个独立的模块页面都可以监听 3 如何实现切换菜单 还要考虑模块化 话不多说直接上代码
先了解 RegionManager ,其次就是Prism 模块的加载机制
项目结构 模块内有两个界面 基础设置 和 甘特图界面
public interface IView
{
}
public class MainWindowViewModel : BindableBase
{
private string _title = "Prism Application";
//Region管理对象
private IRegionManager _regionManager;
private IModuleCatalog _moduleCatalog;
private ObservableCollection<IModuleInfo> _modules;
private DelegateCommand _loadModulesCommand;
private DelegateCommand _openViewA;
private DelegateCommand _openViewB;
private DelegateCommand _goBackView;
private DelegateCommand _goForwardView;
private IModuleInfo _moduleInfo;
//导航日志
private IRegionNavigationJournal _navigationJournal;
public IView View { get; set; }
public string Title
{
get { return _title; }
set { SetProperty(ref _title, value); }
}
public ObservableCollection<IModuleInfo> Modules
{
get => _modules ?? (_modules = new ObservableCollection<IModuleInfo>());
}
public DelegateCommand LoadModulesCommand { get => _loadModulesCommand = new DelegateCommand(InitModules); }
public IModuleInfo ModuleInfo
{
get
{
return _moduleInfo;
}
set
{
_moduleInfo = value;
Navigate(value);
}
}
public DelegateCommand OpenViewA
{
get => _openViewA ?? (_openViewA = new DelegateCommand(OpenViewAAction));
}
public DelegateCommand OpenViewB
{
get => _openViewB ?? (_openViewB = new DelegateCommand(OpenViewBAction));
}
public DelegateCommand GoBackView { get => _goBackView ?? (_goBackView = new DelegateCommand(GoBackViewAction)); }
public DelegateCommand GoForwardView { get => _goForwardView ?? (_goForwardView = new DelegateCommand(GoForwardViewAction)); }
public MainWindowViewModel(IRegionManager regionManager, IModuleCatalog moduleCatalog)
{
_regionManager = regionManager;
_moduleCatalog = moduleCatalog;
}
private void OpenViewAAction()
{
//_regionManager.RequestNavigate("ContentRegion", "TempViewA");
_regionManager.RequestNavigate("ContentRegion", "TempViewA", arg =>
{
//记录导航日志上下文
_navigationJournal = arg.Context.NavigationService.Journal;
});
}
private void OpenViewBAction()
{
//_regionManager.RequestNavigate("ContentRegion", "TempViewB");
_regionManager.RequestNavigate("ContentRegion", "TempViewB", arg =>
{
//记录导航日志上下文
_navigationJournal = arg.Context.NavigationService.Journal;
});
}
///
/// 导航日志:导航到上一个
///
private void GoBackViewAction()
{
if (_navigationJournal.CanGoBack)
{
_navigationJournal.GoBack();
}
}
///
/// 导航日志:导航到下一个
///
private void GoForwardViewAction()
{
if (_navigationJournal.CanGoForward)
{
_navigationJournal.GoForward();
}
}
public void InitModules()
{
//var dirModuleCatalog =;
Modules.AddRange(_moduleCatalog.Modules);
}
private void Navigate(IModuleInfo info)
{
var paramete = new NavigationParameters();
_regionManager.RequestNavigate("ContentRegion", $"{info.ModuleName}View", arg =>
{
//记录导航日志上下文
_navigationJournal = arg.Context.NavigationService.Journal;
});
// _regionManager.RequestNavigate("ContentRegion", $"{info.ModuleName}View", paramete);
}
}
<Window xmlns:dxdo="http://schemas.devexpress.com/winfx/2008/xaml/docking" x:Class="NhxProjectSytem.Main.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
xmlns:dxa="http://schemas.devexpress.com/winfx/2008/xaml/accordion"
prism:ViewModelLocator.AutoWireViewModel="True"
Title="{Binding Title}" Height="350" Width="525" >
<DockPanel>
<dxdo:DockLayoutManager FloatingMode="Desktop" ClosedPanelsBarVisibility="Never">
<dxdo:LayoutGroup Orientation="Horizontal">
<dxdo:LayoutPanel Name="Navigation" Caption="导航" AllowClose="False" ItemWidth="200">
<dxa:AccordionControl ItemsSource="{Binding Modules}" Name="Menus" SelectedItem="{Binding ModuleInfo}" >
<dxa:AccordionControl.ItemContainerStyle>
<Style TargetType="dxa:AccordionItem">
"Header" Value="{Binding ModuleName}"/>
Style>
dxa:AccordionControl.ItemContainerStyle>
dxa:AccordionControl>
dxdo:LayoutPanel>
<dxdo:DocumentPanel >
<ContentControl prism:RegionManager.RegionName="ContentRegion"/>
dxdo:DocumentPanel>
dxdo:LayoutGroup>
dxdo:DockLayoutManager>
DockPanel>
Window>
两种添加模块的方式
public partial class App
{
protected override Window CreateShell()
{
return Container.Resolve<MainWindow>();
}
//protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
//{
// // 1 添加模块
// moduleCatalog.AddModule();
// moduleCatalog.AddModule();
// base.ConfigureModuleCatalog(moduleCatalog);
//}
protected override void ConfigureRegionAdapterMappings(RegionAdapterMappings regionAdapterMappings)
{
base.ConfigureRegionAdapterMappings(regionAdapterMappings);
}
// 2
protected override IModuleCatalog CreateModuleCatalog()
{
return new DirectoryModuleCatalog() { ModulePath = @".\" };
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
}
}
// Module 这个特性只有在反射的时候才生效
[Module(ModuleName = "BasicSetting")]
public class BasicSettingModule : IModule
{
public void OnInitialized(IContainerProvider containerProvider)
{
var regionManager = containerProvider.Resolve<IRegionManager>();
//通过ContentRegion管理导航默认初始页面ContactView
var contentRegion = regionManager.Regions["ContentRegion"];
}
public void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterForNavigation<BasicSettingView>();
}
}
public class BasicSettingViewModel : BindableBase, INavigationAware
{
private string _message;
public string Message
{
get { return _message; }
set { SetProperty(ref _message, value); }
}
public BasicSettingViewModel()
{
Message = "View A from your Prism Module";
}
public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback)
{
bool result = true;
// this is demo code only and not suitable for production. It is generally
// poor practice to reference your UI in the view model. Use the Prism
// IDialogService to help with this.
if (MessageBox.Show("Do you to navigate?", "Navigate?", MessageBoxButton.YesNo) == MessageBoxResult.No)
result = false;
continuationCallback(result);
}
public bool IsNavigationTarget(NavigationContext navigationContext)
{
//是否创建新示例。为true的时候表示不创建新示例,页面还是之前的;如果为false,则创建新的页面。
return true;
}
public void OnNavigatedFrom(NavigationContext navigationContext)
{
//导航离开当前页面前。
}
public void OnNavigatedTo(NavigationContext navigationContext)
{
//导航到当前页面前, 此处可以传递过来的参数以及是否允许导航等动作的控制。
}
}
····
简单 完成 这个模块不同方式卡我了将近两个小时 经过仔细排查和测试才发现这个坑