C# WPF Caliburn.Micro框架下利用Mef加载其它项目界面

简单来说,就是我有个项目是lib库,此时我想要在其他的项目实现对这个库项目的引用,以实现复用的目的。参考原文,咨询了原作者,源码已经丢失,按照文中的方法已经不能完全复现想要的功能。

01

首先创建一个WPF用户控件库项目命名为mycontrol,在项目里新建用户控件timererViewModel,再在项目里建一个窗体TestView。项目结构如下:

02

然后创建一个WPF应用项目,命名为WpfApp3。新建窗体StartView.xaml,项目结构如下:

 

其中MyBootstrapper代码如下

using Caliburn.Micro;
using materialtest.ViewModel;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows;
using WpfApp3.ViewModels;

namespace WpfApp3
{
    class MyBootstrapper : BootstrapperBase
    {


        public MyBootstrapper()
        {
            Initialize();//初始化框架
        }

        //[Import]
        //public MefTestParts mefTestParts { get; set; }
        protected override void OnStartup(object sender, StartupEventArgs e)
        {
            DisplayRootViewFor<StartViewModel>();//显示界面
        }

        /// <summary>
        /// 方法1
        /// </summary>
        //protected void Configure0()
        //{
        //    var envirmentPath = System.IO.Directory.GetCurrentDirectory();
        //    //AssemblyCatalog 目录的一种,表示在程序集中搜索
        //    var assemblyCatalog = new AssemblyCatalog(typeof(StartViewModel).Assembly);//此处这一句实际上没啥用,因为此程序集下没有任何我们需要的实例(各种handler)
        //                                                                               //在某个目录下的dll中搜索。
        //                                                                               //var directoryCatalog = new DirectoryCatalog(@"C:\Program Files (x86)\YWTK\TOOLS\PLUGIN-LIBS\MISC\I12\", "*.dll");
        //    var directoryCatalog = new DirectoryCatalog(envirmentPath, @"materialtest.dll");


        //    var aggregateCatalog = new AggregateCatalog(assemblyCatalog, directoryCatalog);


        //    //创建搜索到的部件,放到容器中。
        //    container = new CompositionContainer(aggregateCatalog);


        //    var batch = new CompositionBatch();      //如果还有自己的部件都加在这个地方
        //    batch.AddExportedValue<IWindowManager>(new WindowManager());
        //    batch.AddExportedValue<IEventAggregator>(new EventAggregator());
        //    batch.AddExportedValue(container);


        //    this.container.Compose(batch);


        //}
        private SimpleContainer container;
        /// <summary>
        /// 方法2
        /// </summary>
        protected override void Configure()
        {
            var envirmentPath = System.IO.Directory.GetCurrentDirectory();


            AssemblySource.Instance.Add(Assembly.LoadFile(Path.Combine(envirmentPath, @"mycontrol.dll")));
            //var catalog = new AggregateCatalog(
            //    AssemblySource.Instance.Select(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>());
            container = new SimpleContainer();

            container.Singleton<SimpleContainer>();

            container.Singleton<IWindowManager, WindowManager>();
            container.Singleton<IEventAggregator, EventAggregator>();
            foreach (var assembly in SelectAssemblies())
            {
                assembly.GetTypes()
               .Where(type => type.IsClass)
               .Where(type => type.Name.EndsWith("ViewModel"))
               .ToList()
               .ForEach(viewModelType => container.RegisterPerRequest(
                   viewModelType, viewModelType.ToString(), viewModelType));
            }
            ExternalLoad();

        }

        private void ExternalLoad()
        {
            var asmPath = Assembly.GetAssembly(typeof(MyBootstrapper)).Location;
            var path = Directory.GetParent(asmPath).FullName;
            string filePath = Path.Combine(path, "mycontrol.dll");

            var assembly = Assembly.LoadFile(filePath);
            assembly.GetTypes()
                    .Where(type => type.IsClass)
                    .Where(type => type.Name.EndsWith("ViewModel"))
                    .ToList()
                     .ForEach(viewModelType => container.RegisterPerRequest(
                       viewModelType, viewModelType.ToString(), viewModelType));

        }
        protected override object GetInstance(Type service, string key)
        {
            return container.GetInstance(service, key);

        }
        private readonly SimpleContainer scontainer = new SimpleContainer();

        protected override IEnumerable<object> GetAllInstances(Type service)
        {
            return container.GetAllInstances(service);
        }
        protected override void BuildUp(object instance)
        {
            container.BuildUp(instance);
        }


        protected override void OnExit(object sender, EventArgs e)
        {
            base.OnExit(sender, e);
            this.Application.Shutdown();
        }


    }




}

 其中核心代码为:

var asmPath = Assembly.GetAssembly(typeof(MyBootstrapper)).Location;
            var path = Directory.GetParent(asmPath).FullName;
            string filePath = Path.Combine(path, "mycontrol.dll");

            var assembly = Assembly.LoadFile(filePath);
//如果运行目录不存在mycontrol.dll,则需要将相应的mycontrol.dll拷贝到运行目录里去

其中StartView.xaml代码如下:

<Window
        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:WpfApp3.Views"
        xmlns:cal="http://www.caliburnproject.org" 
        xmlns:mycontrol="clr-namespace:mycontrol;assembly=mycontrol" x:Class="WpfApp3.Views.StartView" 
        mc:Ignorable="d"
        Title="StartView" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>

        </Grid.RowDefinitions>
        <ContentControl Margin="2" cal:View.Model="{Binding Timerview}"/>

        <GroupBox x:Name="g" Grid.Row="1" MouseLeftButtonDown="g_MouseLeftButtonDown">
            <StackPanel Orientation="Horizontal">
                <CheckBox x:Name="a"/>
                <CheckBox x:Name="b"/>
                <CheckBox x:Name="c"/>
                <CheckBox x:Name="d"/>
                <ContentControl x:Name="ActiveItem"/>

            </StackPanel>
        </GroupBox>
        <GridSplitter Height="3" Grid.Row="0" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Background="Red"/>
        <Button x:Name="open" Content="openwindow" Grid.Row="2" MouseDoubleClick="open_MouseDoubleClick" HorizontalAlignment="Left" VerticalAlignment="Top"/>

    </Grid>
</Window>

其中StartViewModel.cs代码如下:

using Caliburn.Micro;
using materialtest.ViewModel;
using materialtest.Views;
using mycontrol;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WpfApp3.ViewModels
{
    public class StartViewModel:Conductor<object>.Collection.OneActive
    {
        public timererViewModel Timerview { get; set; }
        public StartViewModel()
        {
            Timerview = IoC.Get<timererViewModel>();
            Timerview = new timererViewModel("hello world");
            Timerview.Deactivated += Timerview_Deactivated;
            Timerview.AttemptingDeactivation += Timerview_AttemptingDeactivation;
            Timerview.Activated += Timerview_Activated;
            Timerview.ViewAttached += Timerview_ViewAttached;
            Timerview.ViewAttached += Timerview_ViewAttached1;
            ActivateItem(IoC.Get<timererViewModel>());
        }

        private void Timerview_ViewAttached1(object sender, ViewAttachedEventArgs e)
        {
            
        }

        private void Timerview_ViewAttached(object sender, ViewAttachedEventArgs e)
        {
            
        }

        private void Timerview_Activated(object sender, ActivationEventArgs e)
        {
            throw new NotImplementedException();
        }

        private void Timerview_AttemptingDeactivation(object sender, DeactivationEventArgs e)
        {
            throw new NotImplementedException();
        }

        private void Timerview_Deactivated(object sender, DeactivationEventArgs e)
        {
            throw new NotImplementedException();
        }

        public void open() 
        {
            Timerview.change();

            var winManager =IoC.Get<IWindowManager>();
            var test=IoC.Get<TestViewModel>();
            var  test1=new TestViewModel("都不是啥好人");
            winManager.ShowDialog(test1);
            Console.WriteLine(test1.mzr);
        }
    }
}

这样其它项目的界面就成功的被加载到了我们的主项目中,这样如果我们定义了公共的接口,直接导出接口类型,就很好地实现了主项目和子项目的解耦。

想要免费源码可以私信

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值