• WPF优秀组件推荐之Stylet(二)


    上一篇文章介绍了Stylet的一些基本功能,本篇将介绍一些深入一点的功能。

      

    依赖注入

    在Bootstrapper 类中注入需要的对象:

        public class Bootstrapper : Bootstrapper<MainViewModel>
        {
            protected override void ConfigureIoC(IStyletIoCBuilder builder)
            {
                builder.Bind<IViewFactory>().ToAbstractFactory();
                builder.Bind<ILogger>().To<TxtLogger>().InSingletonScope();
            }
        }

    使用方法:

        public class PageBasicCharacteristicViewModel : Screen
        {
            private readonly IWindowManager _windowManager; 
    private readonly IViewFactory _viewFactory;
    private readonly ILogger _logger; public PageBasicCharacteristicViewModel(IWindowManager windowManager, IViewFactory viewFactory, ILogger logger) { _windowManager = windowManager;
     _viewFactory = viewFactory; _logger
    = logger; } }

     以上IWindowManager 是框架自带的接口,ILog和IViewFactory是我们自己实现的接口。IViewFactory定义如下:

        public interface IViewFactory
        {
            Page1ViewModel Page1ViewModel();
            Page2ViewModel Page2ViewModel();
        }

     由于通过ToAbstractFactory方法来进行注入,不需要对该接口进行实现,但需要满足一定的命名规则。这个方式是Stylet框架的一个小技巧,正常情况下,还是通过一个接口和一个实现类进行注入。

    多窗口界面

    一般而言,系统在功能比较多的情况下都会规划到多个页面中,然后通过菜单来进行导航。实现的方法是,我们会创建一个主界面(ShellView),在主界面上有菜单和一个<ContentControl/>控件,当点击不同菜单时,ContentControl容纳不同的Page即可。注意:此时PageView是一个用户控件(UserControl),而不是窗体(Window)

    XMAL:

    <ContentControl s:View.Model="{Binding ActiveItem}" Margin="5"/>

     CS:

     public class ShellViewModel : Conductor<IScreen>.Collection.OneActive
        {
            private readonly IWindowManager _windowManager;
            private readonly IViewFactory _viewFactory;
    
            public ShellViewModel(IWindowManager windowManager, IViewFactory viewFactory)
            {
                _windowManager = windowManager;
                _viewFactory = viewFactory;
            }
    
            protected override void OnInitialActivate()
            {
                base.OnInitialActivate();
                this.Bind(s => SelectedMenuIndex, (o, e) => SelectedMenuIndexChanged());
            }
    
            public List<string> Menus { get; set; } = new List<string> { "Page1", "Page2" };
            public int SelectedMenuIndex { get; set; } = -1;
    
            private void SelectedMenuIndexChanged()
            {
                switch (SelectedMenuIndex)
                {
                    case 0: ActivateItem(Page1View ?? (Page1View = _viewFactory.Page1ViewModel())); break;
                    case 1: ActivateItem(Page2View ?? (Page2View = _viewFactory.Page2ViewModel())); break;
                }
            }             
    
            private Page1ViewModel Page1View;
            private Page2ViewModel Page2View;        
        }
    View Code

    当SelectedMenuIndex的值变化时,系统将调用SelectedMenuIndexChanged()方法,此时调用ActivateItem(Screen)方法即可切换页面。

    注意ShellViewModel 的父类为Conductor<IScreen>.Collection.OneActive

    以上代码保存了一个ViewModel的实例,根据需要,我们也可以每次打开页面时都创建一个新的ViewModel对象。

    页面的生命周期

    不管是从Window继承的窗口还是从UserControl继承的用户控件,Stylet处理的模型是一致的,都是View+ViewModel模式,且生命周期也类似。

    一个Model大概有以下几个生命周期:

            protected override void OnInitialActivate()
            {
                base.OnInitialActivate();
            }
    
            protected override void OnViewLoaded()
            {
                base.OnViewLoaded();
            }
    
            protected override void OnActivate()
            {
                base.OnActivate();
            }
    
            protected override void OnDeactivate()
            {
                base.OnDeactivate();
            }
    
            protected override void OnClose()
            {
                base.OnClose();
            }
    View Code

     其调用时机和顺序大家可以自己试验一下。

    事件

    在有多个页面时,可能需要进行页面间的通信,Stylet框架通过事件(Event)来实现。

    事件的定义:

        public class SomeEvent: PropertyChangedBase
        {
            public SomeEventArgs Args { get; set; }
        }
    
        public class SomeEventArgs 
        {
            public string Msg { get; set; }
        }

    发布事件:

        public class Page1ViewModel : Screen
        {
            private readonly IEventAggregator _events;
    
            public Page1ViewModel(IEventAggregator events)
            {
                _events = events;
            }   
    
            public string Message { get; set; }
            public void SendMessage()
            {          
                _events.Publish(new SomeEvent
                {
                    Args = new SomeEventArgs
                    {
                        Msg = Message
                    }
                });
            }
        }

    订阅事件:

        public class Page2ViewModel : Screen, IHandle<SomeEvent>
        {
            private readonly IEventAggregator _events;
    
            public Page2ViewModel(IEventAggregator events)
            {
                _events = events;
                _events.Subscribe(this);
            }
    
            public string RecvMsg { get; set; }
            public void Handle(SomeEvent message)
            {           
                RecvMsg = "RecvMsg=" + message.Args.Msg;
            }
        }

    ViewModel通过继承IHandle<SomeEvent>实现事件消息的处理,注意: _events.Subscribe(this);这段代码非常重要,必须订阅事件,不然收不到消息。

    以上代码下载地址:NiceComponents · Bruce/Learn WPF - 码云 - 开源中国 (gitee.com)

  • 相关阅读:
    SpringBoot项目中遇到的BUG
    关于Unsupported major.minor version 52.0报错问题解决方案
    spring官网上下载历史版本的spring插件,springsource-tool-suite
    构建微服务:Spring boot 入门篇
    Spring Cloud 入门教程(一): 服务注册
    SpringCloud是什么?
    ubuntu下查看windows的 txt 文件乱码
    Ubuntu 14.04 LTS中怎样安装fcitx中文输入法
    eclipse调用jni
    Ubuntu 12.04 分区方案(仅供参考)
  • 原文地址:https://www.cnblogs.com/seabluescn/p/15932105.html
Copyright © 2020-2023  润新知