WPF Prism IRegionManager, IContainerRegistry implements IOC, IModule implements module management,IEventAggregator implements message broadcast via Publish,Subscribe,PubSubEvent<T>
//Install-Package for the whole solution Get-Project -All | Install-Package Prism.Wpf; Get-Project -All | Install-Pacjage Prism.DryIoc;
The whole structure as below,WpfApp29 as the start up application, other projects are all modified as class library project

using BookProject; using ImageProject; using System.Configuration; using System.Data; using System.Windows; using WpfApp29.Service; using WpfApp29.ViewModels; namespace WpfApp29 { /// <summary> /// Interaction logic for App.xaml /// </summary> public partial class App : PrismApplication { protected override Window CreateShell() { return Container.Resolve<MainWindow>(); } protected override void OnInitialized() { base.OnInitialized(); var regionManager = Container.Resolve<IRegionManager>(); regionManager.RequestNavigate("MainRegion", "BookView"); } protected override void RegisterTypes(IContainerRegistry containerRegistry) { containerRegistry.Register<ITimeService, TimeService>(); containerRegistry.RegisterForNavigation<MainWindow, MainWindowViewModel>(); } protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog) { base.ConfigureModuleCatalog(moduleCatalog); moduleCatalog.AddModule<BookModule>(); moduleCatalog.AddModule<ImageModule>(); } } }




//Runtime project using System; using System.Collections.Generic; using System.Text; namespace Runtime.Common.Models { public class MsgPayLoad { public int Idx { get; set; } public string TimeStr { get; set; } public string Msg { get; set; } } public class MsgPayLoadEvent : PubSubEvent<MsgPayLoad> { } } //BookProject using System; using System.Collections.Generic; using System.Text; namespace BookProject.Models { public class Book { public int Id { get; set; } public string Name { get; set; } public string ISBN { get; set; } public string Title { get; set; } public string Topic { get; set; } } } using System; using System.Collections.Generic; using System.Text; namespace BookProject.Services { public interface IIDService { int GetID(); } public class IDService : IIDService { int id = 0; public int GetID() { return Interlocked.Increment(ref id); } } public interface INameService { string GetName(); } public class NameService : INameService { int idx = 0; public string GetName() { return $"Name_{Interlocked.Increment(ref idx)}"; } } public interface IISBNService { string GetISBN(); } public class ISBNService : IISBNService { int idx = 0; public string GetISBN() { return $"ISBN_{Interlocked.Increment(ref idx)}_{Guid.NewGuid():N}"; } } } using BookProject.Models; using BookProject.Services; using Runtime.Common.Models; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Text; using System.Windows.Shell; namespace BookProject.ViewModels { public class BookViewModel : BindableBase { IIDService idService; INameService nameService; IISBNService isbnService; IEventAggregator eventAggregator; public BookViewModel(IIDService idServiceValue, INameService nameServiceValue, IISBNService isbnServiceValue,IEventAggregator eventAggregatorValue) { idService = idServiceValue; nameService = nameServiceValue; isbnService = isbnServiceValue; eventAggregator = eventAggregatorValue; } public async Task InitBooksCollectionAsync() { BooksCollection = new ObservableCollection<Book>(); List<Book> booksList = new List<Book>(); for (int i = 1; i < 10000001; i++) { booksList.Add(new Book() { Id = idService.GetID(), Name = nameService.GetName(), ISBN = isbnService.GetISBN(), Title = $"Title_{1}", Topic = $"Topic_{i}" }); if (i % 100000 == 0) { await PopulateBooksCollectionAsync(booksList); } } if(booksList.Any()) { await PopulateBooksCollectionAsync(booksList); } MsgPayLoad msgLoad = new MsgPayLoad() { Idx = BooksCollection.LastOrDefault().Id, TimeStr = $"Now:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}", Msg = $"Loaded {BooksCollection.Count} items finished!" }; eventAggregator.GetEvent<MsgPayLoadEvent>().Publish(msgLoad); } private async Task PopulateBooksCollectionAsync(List<Book> booksList) { var tempList = booksList.ToList(); booksList.Clear(); await System.Windows.Application.Current.Dispatcher.InvokeAsync(() => { foreach (var book in tempList) { BooksCollection.Add(book); } MsgPayLoad msgLoad = new MsgPayLoad() { Idx = tempList.LastOrDefault().Id, TimeStr=$"Now:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}", Msg=$"Loaded {BooksCollection.Count} items" }; eventAggregator.GetEvent<MsgPayLoadEvent>().Publish(msgLoad); }, System.Windows.Threading.DispatcherPriority.Background); } private ObservableCollection<Book> booksCollection; public ObservableCollection<Book> BooksCollection { get { return booksCollection; } set { SetProperty(ref booksCollection, value); } } } } <UserControl x:Class="BookProject.Views.BookView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:BookProject.Views" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800" xmlns:prism="http://prismlibrary.com/" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" prism:ViewModelLocator.AutoWireViewModel="True"> <Grid> <DataGrid ItemsSource="{Binding BooksCollection}" VirtualizingPanel.IsVirtualizing="True" VirtualizingPanel.VirtualizationMode="Recycling" VirtualizingPanel.CacheLength="2,2" VirtualizingPanel.CacheLengthUnit="Item" ScrollViewer.IsDeferredScrollingEnabled="True" ScrollViewer.CanContentScroll="True" AutoGenerateColumns="True" CanUserAddRows="False" FontSize="30"/> </Grid> </UserControl> using BookProject.ViewModels; using System; using System.Collections.Generic; using System.Text; 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; namespace BookProject.Views { /// <summary> /// Interaction logic for BookView.xaml /// </summary> public partial class BookView : UserControl { public BookView() { InitializeComponent(); this.Loaded += async (s, e) => { var vm = this.DataContext as BookViewModel; if (vm != null) { await vm.InitBooksCollectionAsync(); } }; } } } using BookProject.Services; using BookProject.ViewModels; using BookProject.Views; using System; using System.Collections.Generic; using System.Text; namespace BookProject { public class BookModule : IModule { public void OnInitialized(IContainerProvider containerProvider) { } public void RegisterTypes(IContainerRegistry containerRegistry) { containerRegistry.Register<IIDService, IDService>(); containerRegistry.Register<INameService, NameService>(); containerRegistry.Register<IISBNService, ISBNService>(); containerRegistry.RegisterForNavigation<BookView, BookViewModel>("BookView"); } } } //ImageProject using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Text; using System.Windows.Media; using System.Windows.Media.Imaging; namespace ImageProject.Services { public interface IImageService { ImageSource GetImgSourceViaUrl(string imgUrl); } public class ImageService : IImageService { private ConcurrentDictionary<string, ImageSource> imgDicCache = new ConcurrentDictionary<string, ImageSource>(); public ImageSource GetImgSourceViaUrl(string imgUrl) { if (!File.Exists(imgUrl)) { BitmapImage nullBmi = new BitmapImage(); return nullBmi; } if (imgDicCache.TryGetValue(imgUrl, out ImageSource imgSource)) { return imgSource; } BitmapImage bmi = new BitmapImage(); bmi.BeginInit(); bmi.UriSource = new Uri(imgUrl, UriKind.RelativeOrAbsolute); bmi.EndInit(); if (bmi.CanFreeze) { bmi.Freeze(); } imgDicCache[imgUrl] = bmi; return bmi; } } } using ImageProject.Services; using Runtime.Common.Models; using System; using System.Collections.Generic; using System.IO; using System.Text; using System.Windows.Media; namespace ImageProject.ViewModels { public class ImageViewModel:BindableBase { ImageService imageService; IEventAggregator eventAggregator; List<string> imgsUrlList = new List<string>(); int imgsCount = 0; int imgIdx = 0; public ImageViewModel(IEventAggregator eventAggregatorValue,ImageService imageServiceValue) { eventAggregator = eventAggregatorValue; imageService = imageServiceValue; } public void InitImageSource() { var dir = @"Images"; if(!Directory.Exists(dir)) { return; } imgsUrlList = new List<string>(Directory.GetFiles(dir)); if(!imgsUrlList.Any() ) { return; } imgsCount = imgsUrlList.Count; ImgUrl = imgsUrlList[(++imgIdx) % imgsCount]; ImgSource = imageService.GetImgSourceViaUrl(ImgUrl); Task.Run(() => { InitTimer(); }); } private void InitTimer() { System.Timers.Timer tmr = new System.Timers.Timer(); tmr.Elapsed += Tmr_Elapsed; tmr.Interval = 1000; tmr.Start(); } private void Tmr_Elapsed(object? sender, System.Timers.ElapsedEventArgs e) { System.Windows.Application.Current.Dispatcher.InvokeAsync(() => { ImgUrl = System.IO.Path.GetFullPath(imgsUrlList[(++imgIdx) % imgsCount]); ImgSource = imageService.GetImgSourceViaUrl(ImgUrl); }); MsgPayLoad msgPayLoad = new MsgPayLoad() { Idx = imgIdx, TimeStr = $"Now:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}", Msg = System.IO.Path.GetFullPath(ImgUrl) }; eventAggregator.GetEvent<MsgPayLoadEvent>().Publish(msgPayLoad); } private string imgUrl; public string ImgUrl { get { return imgUrl; } set { SetProperty(ref imgUrl, value); } } private ImageSource imgSource; public ImageSource ImgSource { get { return imgSource; } set { SetProperty(ref imgSource, value); } } } } <UserControl x:Class="ImageProject.Views.ImageView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:ImageProject.Views" xmlns:prism="http://prismlibrary.com/" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" prism:ViewModelLocator.AutoWireViewModel="True" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> <Grid> <Grid.Background> <ImageBrush ImageSource="{Binding ImgSource}" Stretch="Uniform"/> </Grid.Background> <TextBlock Text="{Binding ImgUrl}" FontSize="30" Foreground="Red" TextWrapping="Wrap" HorizontalAlignment="Center" VerticalAlignment="Center"/> </Grid> </UserControl> using ImageProject.ViewModels; using System; using System.Collections.Generic; using System.Text; 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; namespace ImageProject.Views { /// <summary> /// Interaction logic for ImageView.xaml /// </summary> public partial class ImageView : UserControl { public ImageView() { InitializeComponent(); this.Loaded += async (s, e) => { var vm = this.DataContext as ImageViewModel; if (vm != null) { vm.InitImageSource(); } }; } } } using ImageProject.Services; using ImageProject.ViewModels; using ImageProject.Views; using System; using System.Collections.Generic; using System.Text; namespace ImageProject { public class ImageModule : IModule { public void OnInitialized(IContainerProvider containerProvider) { var regionManager= containerProvider.Resolve<IRegionManager>(); } public void RegisterTypes(IContainerRegistry containerRegistry) { containerRegistry.Register<IImageService, ImageService>(); containerRegistry.RegisterForNavigation<ImageView, ImageViewModel>("ImageView"); } } } //WpfApp29 as startup application using System; using System.Collections.Generic; using System.Text; namespace WpfApp29.Service { public interface ITimeService { string GetTimeNow(); } public class TimeService:ITimeService { int idx = 0; public string GetTimeNow() { return $"{Interlocked.Increment(ref idx)}_{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}"; } } } using BookProject.Models; using Prism.Events; using Runtime.Common.Models; using System; using System.Collections.Generic; using System.Text; using WpfApp29.Service; namespace WpfApp29.ViewModels { public class MainWindowViewModel:BindableBase { ITimeService timeService; IContainerProvider containerProvider; IRegionManager regionManager; IEventAggregator eventAggregator; public MainWindowViewModel(ITimeService timeServiceValue, IContainerProvider containerProviderValue, IEventAggregator eventAggregatorValue) { timeService= timeServiceValue; containerProvider= containerProviderValue; eventAggregator = eventAggregatorValue; eventAggregator.GetEvent<MsgPayLoadEvent>().Subscribe(OnStatusMsgEventReceived); regionManager = containerProvider.Resolve<IRegionManager>(); TimeStr = timeService.GetTimeNow(); MainStatus = "Ready..."; NavigateCommand = new DelegateCommand<string>(NavigateCommandExecuted); Task.Run(() => { InitTimer(); }); } private void OnStatusMsgEventReceived(MsgPayLoad load) { MainStatus = $"{load.Idx},{load.TimeStr},{load.Msg}"; } private void NavigateCommandExecuted(string viewName) { regionManager.RequestNavigate("MainRegion", viewName); } private void InitTimer() { System.Timers.Timer tmr=new System.Timers.Timer(); tmr.Elapsed += Tmr_Elapsed; tmr.Interval = 1000; tmr.Start(); } private void Tmr_Elapsed(object? sender, System.Timers.ElapsedEventArgs e) { TimeStr = timeService.GetTimeNow(); } public DelegateCommand<string> NavigateCommand { get; set; } private string timeStr; public string TimeStr { get { return timeStr; } set { SetProperty(ref timeStr, value); } } private string mainStatus; public string MainStatus { get { return mainStatus; } set { SetProperty(ref mainStatus, value); } } } } <prism:PrismApplication x:Class="WpfApp29.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApp29" xmlns:prism="http://prismlibrary.com/"> </prism:PrismApplication> using BookProject; using ImageProject; using System.Configuration; using System.Data; using System.Windows; using WpfApp29.Service; using WpfApp29.ViewModels; namespace WpfApp29 { /// <summary> /// Interaction logic for App.xaml /// </summary> public partial class App : PrismApplication { protected override Window CreateShell() { return Container.Resolve<MainWindow>(); } protected override void OnInitialized() { base.OnInitialized(); var regionManager = Container.Resolve<IRegionManager>(); regionManager.RequestNavigate("MainRegion", "BookView"); } protected override void RegisterTypes(IContainerRegistry containerRegistry) { containerRegistry.Register<ITimeService, TimeService>(); containerRegistry.RegisterForNavigation<MainWindow, MainWindowViewModel>(); } protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog) { base.ConfigureModuleCatalog(moduleCatalog); moduleCatalog.AddModule<BookModule>(); moduleCatalog.AddModule<ImageModule>(); } } } <Window x:Class="WpfApp29.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:WpfApp29" xmlns:prism="http://prismlibrary.com/" WindowState="Maximized" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Grid Grid.Row="0"> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <TextBlock Text="{Binding TimeStr}" FontSize="30" Grid.Column="0"/> <Button Content="DgView" Command="{Binding NavigateCommand}" CommandParameter="BookView" Grid.Column="1"/> <Button Content="ImageView" Command="{Binding NavigateCommand}" CommandParameter="ImageView" Grid.Column="2"/> </Grid> <ContentControl Grid.Row="1" prism:RegionManager.RegionName="MainRegion" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"/> <TextBlock Grid.Row="2" Text="{Binding MainStatus}" FontSize="30"/> </Grid> </Window>

浙公网安备 33010602011771号