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)
簽名區:
如果您覺得這篇部落格對您有幫助或啟發,請點選右側【推薦】支援,謝謝!