[DX_WPF] Dynamic Load Modules In DevExpress MVVM For WPF
방식 1.
Libaray Nuget Package
https://github.com/dlsenfl3/DXDynamicModule
Nuget 추가.
사용.
https://github.com/dlsenfl3/DXModularWithDynamic
App.xaml.cs
Project Module
ViewModelSource 나 ViewModelBase 둘중 하나만 사용. (같은 거)
ViewModelSource and ViewModelBase are interchangeable solutions that should not be used together.
Understanding POCOViewModel / ViewModelBase with ViewModelSource.Create()
You have yet to view any tickets. Your search criteria do not match any tickets. A server error occurred while processing your request. Please try again at a later time.
supportcenter.devexpress.com
View
주석 처리된 부분 풀리면 생성자 2번 불림.
ViewModelSource 사용 시
선언 안해도 (new Module 할 때 뷰 지정해줘서?!)실질적으로 바인딩되어 사용가능?
ModuleDViewModel.Create 사용해야
this.RaisePropertiesChanged();
Raise~ 사용가능.
ViewModelBase 사용시
둘 다 사용가능?!
DevExpress MVVM Framework. Interaction of ViewModels. IDocumentManagerService.
OTHER RELATED ARTICLES: Getting Started with DevExpress MVVM Framework. Commands and View Models.DevExpress MVVM Framework. Introduction to Services, DXMessageBoxService and DialogService.THIS POST: DevExpress MVVM Framework. Interaction of ViewModels. ID
community.devexpress.com
Service 등록/사용
DevExpress MVVM Framework. Introduction to POCO ViewModels.
OTHER RELATED ARTICLES: Getting Started with DevExpress MVVM Framework. Commands and View Models.DevExpress MVVM Framework. Introduction to Services, DXMessageBoxService and DialogService.DevExpress MVVM Framework. Interaction of ViewModels. IDocumentManag
community.devexpress.com
방식2.
module Dynamic load
런타임시 모듈 동적 로드
App.xaml.cs
using System;
using DevExpress.Mvvm;
using DevExpress.Mvvm.ModuleInjection;
using DevExpress.Mvvm.UI;
using DevExpress.Xpf.Core;
using DXApplication1.Common;
using DXApplication1.Main.Properties;
using DXApplication1.Main.ViewModels;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows;
using AppModules = DXApplication1.Common.Modules;
using DevExpress.Data.Utils;
using DXApplication1.Main.Views;
namespace DXApplication1.Main
{
public partial class App : Application
{
public App()
{
ApplicationThemeHelper.UpdateApplicationThemeName();
SplashScreenManager.CreateThemed().ShowOnStartup();
}
protected override void OnExit(ExitEventArgs e)
{
ApplicationThemeHelper.SaveApplicationThemeName();
base.OnExit(e);
}
void OnApplicationStartup(object sender, StartupEventArgs e)
{
Bootstrapper.Run();
}
}
public class Bootstrapper
{
private List<Assembly> assemblies = new List<Assembly>();
private List<string> keyNames = new List<string>();
public List<DevExpress.Mvvm.ModuleInjection.Module> modules = new List<DevExpress.Mvvm.ModuleInjection.Module>();
public static Bootstrapper Default { get; protected set; }
public static void Run()
{
Default = new Bootstrapper();
Default.RunCore();
}
protected Bootstrapper() { }
const string StateVersion = "1.0";
public virtual void RunCore()
{
ConfigureTypeLocators();
RegisterModules();
if (!RestoreState())
InjectModules();
ConfigureNavigation();
ShowMainWindow();
}
protected IModuleManager Manager { get { return ModuleManager.DefaultManager; } }
protected virtual void ConfigureTypeLocators()
{
assemblies.Add(typeof(MainViewModel).Assembly);
//var mainAssembly = typeof(MainViewModel).Assembly;
//var modulesAssembly = typeof(ModuleViewModel).Assembly;
//var assemblies = new[] { mainAssembly, modulesAssembly };
//ViewModelLocator.Default = new ViewModelLocator(assemblies);
//ViewLocator.Default = new ViewLocator(assemblies);
}
protected virtual void RegisterModules()
{
Manager.GetRegion(Regions.Documents).VisualSerializationMode = VisualSerializationMode.PerKey;
Manager.Register(Regions.MainWindow, new DevExpress.Mvvm.ModuleInjection.Module(AppModules.Main, ()=>MainViewModel.Create(), typeof(MainView)));
// First, find all modules
var foundModules = Directory.EnumerateFiles(System.Environment.CurrentDirectory, "*.Modules.dll", SearchOption.AllDirectories);
if (foundModules.Count() == 0)
return;
foreach (var item in foundModules)
{
var asm = Assembly.LoadFrom(item);
foreach (Type type in asm.GetTypes())
{
MethodInfo info = type.GetMethod("Create");
if (info == null)
continue;
assemblies.Add(asm);
string keyField = (string)type.GetProperty("Key").GetValue(type); // returns ModuleViewModel
string viewName = (string)type.GetProperty("ViewName").GetValue(type); // returns ModuleView
keyNames.Add(keyField);
var module = new DevExpress.Mvvm.ModuleInjection.Module(keyField, () => info.Invoke(null, new object[] {$"{keyField}Module" }), viewName);
modules.Add(module);
}
}
// Update view locator(s)
ViewModelLocator.Default = new ViewModelLocator(assemblies);
ViewLocator.Default = new ViewLocator(assemblies);
// Register all modules
modules.ForEach(module => Manager.Register(Regions.Documents, module));
modules.ForEach(module => Manager.Register(Regions.Navigation, module));
//if(keyNames.Where(key => key == "ModuleViewModel").Any())
//{
//}
//Manager.Register(Regions.Navigation, new DevExpress.Mvvm.ModuleInjection.Module(keyNames.Where(key => key == "ModuleViewModel").FirstOrDefault(), () => new NavigationItem("Module1")));
//Manager.Register(Regions.Navigation, new DevExpress.Mvvm.ModuleInjection.Module(AppModules.Module1, () => new NavigationItem("Module1")));
//Manager.Register(Regions.Navigation, new DevExpress.Mvvm.ModuleInjection.Module(AppModules.Module2, () => new NavigationItem("Module2")));
//Manager.Register(Regions.Documents, new Module(AppModules.Module1, () => ModuleViewModel.Create("Module1"), typeof(ModuleView)));
//Manager.Register(Regions.Documents, new Module(AppModules.Module2, () => ModuleViewModel.Create("Module2"), typeof(ModuleView)));
}
protected virtual bool RestoreState()
{
#if !DEBUG
if (Settings.Default.StateVersion != StateVersion) return false;
return Manager.Restore(Settings.Default.LogicalState, Settings.Default.VisualState);
#else
return false;
#endif
}
protected virtual void InjectModules()
{
Manager.Inject(Regions.MainWindow, AppModules.Main);
keyNames.ForEach(key => Manager.Inject(Regions.Navigation, key)); // key = ModuleViewModel
//Manager.Inject(Regions.Navigation, keyNames.Where(key => key == "ModuleViewModel").FirstOrDefault());
//Manager.Inject(Regions.Navigation, keyNames.Where(key => key == "ModuleViewModel").FirstOrDefault());
//Manager.Inject(Regions.Navigation, AppModules.Module1);
//Manager.Inject(Regions.Navigation, AppModules.Module2);
}
protected virtual void ConfigureNavigation()
{
Manager.GetEvents(Regions.Navigation).Navigation += OnNavigation;
Manager.GetEvents(Regions.Documents).Navigation += OnDocumentsNavigation;
}
protected virtual void ShowMainWindow()
{
App.Current.MainWindow = new MainWindow();
App.Current.MainWindow.Show();
App.Current.MainWindow.Closing += OnClosing;
}
void OnNavigation(object sender, NavigationEventArgs e)
{
if (e.NewViewModelKey == null) return;
Manager.InjectOrNavigate(Regions.Documents, e.NewViewModelKey);
}
void OnDocumentsNavigation(object sender, NavigationEventArgs e)
{
Manager.Navigate(Regions.Navigation, e.NewViewModelKey);
}
void OnClosing(object sender, CancelEventArgs e)
{
string logicalState;
string visualState;
Manager.Save(out logicalState, out visualState);
Settings.Default.StateVersion = StateVersion;
Settings.Default.LogicalState = logicalState;
Settings.Default.VisualState = visualState;
Settings.Default.Save();
}
}
}
MainViewModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using DevExpress.Mvvm;
using DevExpress.Mvvm.ModuleInjection;
using DevExpress.Mvvm.POCO;
using DXApplication1.Common;
namespace DXApplication1.Main.ViewModels
{
public class MainViewModel
{
protected IModuleManager Manager { get { return ModuleManager.DefaultManager; } }
//private List<DevExpress.Mvvm.ModuleInjection.Module> modules = new List<DevExpress.Mvvm.ModuleInjection.Module>();
public List<DevExpress.Mvvm.ModuleInjection.Module> modules { get; private set; }
public string Caption { get; private set; }
public static MainViewModel Create(string caption = null)
{
return ViewModelSource.Create(() => new MainViewModel() { Caption = caption });
}
private DelegateCommand testButtonCommand;
public DelegateCommand TestButtonCommand =>
testButtonCommand ?? (testButtonCommand = new DelegateCommand(ExecuteTestButtonCommand));
void ExecuteTestButtonCommand()
{
//Manager.RegisterOrInjectOrNavigate(Regions.Documents, modules.Where(x=>x.Key == "ModuleViewModel").FirstOrDefault());
var key = Guid.NewGuid().ToString().Replace("-", "");
var weakRef = new WeakReference(Bootstrapper.Default.modules.Where(module => module.Key == "ModuleViewModel").FirstOrDefault().ViewModelFactory.Invoke());
var module = new DevExpress.Mvvm.ModuleInjection.Module(
key,
//Bootstrapper.Default.modules.Where(module => module.Key == "ModuleViewModel").FirstOrDefault().ViewModelFactory,
() => weakRef.Target,
Bootstrapper.Default.modules.Where(module => module.Key == "ModuleViewModel").FirstOrDefault().ViewName);
Manager.Register(Regions.Navigation, module);
Manager.Inject(Regions.Navigation, key);
Manager.RegisterOrInjectOrNavigate(Regions.Documents, module);
}
}
}
ModuleViewModel.cs
using DevExpress.Mvvm;
using DevExpress.Mvvm.POCO;
using DXApplication1.Common;
using System;
using System.Collections.ObjectModel;
using System.Linq;
using DXApplication1.Modules.Views;
namespace DXApplication1.Modules.ViewModels
{
public class ModuleViewModel : IDocumentModule, ISupportState<ModuleViewModel.Info>
{
public static string Key => nameof(ModuleViewModel);
public static string ViewModelName => nameof(ModuleViewModel);
public static string ViewName => nameof(ModuleView);
public static Type ViewType => typeof(ModuleView);
public string Caption { get; private set; }
public virtual bool IsActive { get; set; }
public ObservableCollection<DataItem> Items { get; private set; }
public static ModuleViewModel Create(string caption = "module")
{
return ViewModelSource.Create(() => new ModuleViewModel()
{
Caption = caption,
});
}
//public static ModuleViewModel Create(string caption = "module")
//{
// return ViewModelSource.Create(() => new ModuleViewModel()
// {
// Caption = caption,
// });
//}
protected ModuleViewModel()
{
Items = new ObservableCollection<DataItem>();
Enumerable.Range(0, 100)
.Select(x => new DataItem() { Id = x, Value = "Item #" + x.ToString() })
.ToList()
.ForEach(x => Items.Add(x));
}
#region Serialization
[Serializable]
public class Info
{
public string Caption { get; set; }
}
Info ISupportState<Info>.SaveState()
{
return new Info()
{
Caption = this.Caption,
};
}
void ISupportState<Info>.RestoreState(Info state)
{
this.Caption = state.Caption;
}
#endregion
}
public class DataItem
{
public int Id { get; set; }
public string Value { get; set; }
}
}
https://supportcenter.devexpress.com/ticket/details/t868054/mif-and-dynamically-loaded-dlls
MIF and dynamically loaded DLLs
You have yet to view any tickets. Your search criteria do not match any tickets. A server error occurred while processing your request. Please try again at a later time.
supportcenter.devexpress.com
MIF - creating Module with ViewModel instance (instead of ViewModelFactory)
You have yet to view any tickets. Your search criteria do not match any tickets. A server error occurred while processing your request. Please try again at a later time.
supportcenter.devexpress.com
DevExpress MVVM for WPF - New Module Injection Framework Coming Soon in v16.2
Wait, what? What’s a Module Injection Framework – or MIF – and how is it used? The mile-high overview is that a MIF makes it easier to develop, test, maintain, and deploy applications built with loosely-coupled modules. Such a modular application is
community.devexpress.com
https://docs.devexpress.com/WPF/118614/mvvm-framework/mif
MIF | WPF Controls | DevExpress Documentation
Module Injection Framework (MIF) is a set of classes that help organize an MVVM application. It provides the following functionality: Connecting View Models to Views Navigating among different screens or pages in an application Saving and restoring an appl
docs.devexpress.com