DevExpress/DX_WPF

[DX_WPF] Dynamic Load Modules In DevExpress MVVM For WPF

딸기우유중독 2023. 11. 23. 11:07

방식 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.

 

https://supportcenter.devexpress.com/ticket/details/t1148859/understanding-pocoviewmodel-viewmodelbase-with-viewmodelsource-create

 

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 사용시

둘 다 사용가능?!

 

 


 

 

 

 

 

 

https://community.devexpress.com/blogs/wpf/archive/2013/10/09/devexpress-mvvm-framework-interaction-of-viewmodels-idocumentmanagerservice.aspx

 

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 등록/사용

 

https://community.devexpress.com/blogs/wpf/archive/2013/12/03/devexpress-mvvm-framework-introduction-to-poco-viewmodels.aspx

 

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
0.01MB
MainViewModel.cs
0.00MB
ModuleViewModel.cs
0.00MB

 

런타임시 모듈 동적 로드

 

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

 

https://supportcenter.devexpress.com/ticket/details/t710596/mif-creating-module-with-viewmodel-instance-instead-of-viewmodelfactory

 

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

 


 

https://community.devexpress.com/blogs/ctodx/archive/2016/12/02/devexpress-mvvm-for-wpf-new-module-injection-framework-coming-soon-in-v16-2.aspx

 

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

 

 

728x90