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