【本系列須要具備必定開發基礎】git
咱們在開發中常常遇到這樣的場景:github
1.呈現詳細信息,且包含一些操做。如:查看原圖,支持放大,縮小,多圖。緩存
2.執行特定的行爲,且要有回執結果。如:選擇聯繫人,選中某圖,用戶登陸。ide
廣泛的解決方案就是封裝一個UserControl放到頁面裏,控制其顯隱性。若是功能不多,那無所謂,可稍微複雜一點的,封裝成單獨的一個頁面不是更好嗎?還能節省當前頁面的資源。此方法可以解決場景1,可是場景2須要回執結果,又該怎麼辦,總不能用全局變量吧。PageUserControl就是主要解決這些問題而封裝,它將包含特定邏輯的頁面封裝成僞控件,使其能夠單獨調用,且能夠反饋執行結果。ui
調用方法如圖:this
PageUserControlspa
PageUserControl是一個抽象的泛型類,做爲封裝控件的父類。原理:監聽Frame的Navigated事件,利用緩存的兩個頁面變量,區別出是Forward仍是Back,而後分別作傳值和取值操做。廢話很少說,直接上代碼:code
public abstract class PageUserControl<TPage> where TPage : Page { private const string _FrameNameInFramePage = "childrenFrame"; private Frame _frame; private object _frameContentWhenOpened; private TPage _page; /// <summary> /// 獲取是否優先呈如今ChildrenFrame中。 /// </summary> public bool IsChildrenFrameFirst { get; protected set; } #region Methods protected void ShowPage() { this.OpenPickerPage(); } protected void ShowPage(object parameter) { this.OpenPickerPage(parameter); } //若需向調用者返回某值,則須要實現此方法。 protected virtual void CommitValue(TPage page) { } private void OpenPickerPage(object parameter = null) { if (null == _frame) { _frame = Window.Current.Content as Frame; if (null != _frame) { //這裏是約定MainPage頁中childrenFrame是子Frame。 //此方法並不是絕對,仍有不少靈活的方法能夠擴展,好比附加屬性來指定誰是ChildrenFrame。 if (this.IsChildrenFrameFirst && this._frame.CurrentSourcePageType.Equals(typeof(Pages.MainPage))) { var framePage = (Pages.MainPage)_frame.Content; var frameInFramePage = framePage.FindName(_FrameNameInFramePage) as Frame; if (frameInFramePage != null) { this._frame = frameInFramePage; } } _frameContentWhenOpened = _frame.Content; _frame.Navigated += OnFrameNavigated; _frame.NavigationStopped += OnFrameNavigationStopped; _frame.NavigationFailed += OnFrameNavigationFailed; if (parameter == null) { _frame.Navigate(typeof(TPage)); } else { _frame.Navigate(typeof(TPage), parameter); } } } } private void ClosePickerPage() { // 註銷事件 if (null != _frame) { _frame.Navigated -= OnFrameNavigated; _frame.NavigationStopped -= OnFrameNavigationStopped; _frame.NavigationFailed -= OnFrameNavigationFailed; _frame = null; _frameContentWhenOpened = null; } //若緩存頁面有值,則嘗試作提交處理。 if (null != this._page) { this.CommitValue(this._page); this._page = null; } } #endregion #region Events private void OnFrameNavigated(object sender, NavigationEventArgs e) { //如果Back則作關閉處理,如果Forward則把新頁緩存。 if (e.Content == _frameContentWhenOpened) { ClosePickerPage(); } else if (null == this._page) { var page = e.Content as TPage; if (page != null) { this._page = page; } } } private void OnFrameNavigationFailed(object sender, NavigationFailedEventArgs e) { ClosePickerPage(); } private void OnFrameNavigationStopped(object sender, NavigationEventArgs e) { ClosePickerPage(); } #endregion }
以上的代碼對Frame作了簡單擴展,使其能支持在子Frame中呈現(主要是考慮到UWP的SpiltView),可是採用的固定約束,並不靈活。各位看官能夠自行擴展,好比:使用附加屬性來標識某一個Frame,這裏就不實現了。blog
public class ImageChooser : PageUserControl<ImageChooserPage> { public ImageChooser() { //優先在ChildrenFrame呈現。 base.IsChildrenFrameFirst = true; } public void Show() { base.ShowPage(); } protected override void CommitValue(ImageChooserPage page) { base.CommitValue(page); //若標識結果的頁面屬性值有效,則經過事件拋給調用者。 if (!string.IsNullOrWhiteSpace(page.Value)) { this.OnCompleted(page.Value); } } public event EventHandler<ChooseImageCompletedEventArgs> Completed; private void OnCompleted(string image) { var handler = this.Completed; if (handler != null) { handler(this, new ChooseImageCompletedEventArgs(image)); } } } public class ChooseImageCompletedEventArgs : EventArgs { public string Image { get; private set; } internal ChooseImageCompletedEventArgs(string image) { this.Image = image; } }
以上代碼是針對須要返回值的場景,若是無須返回值則留空或者不重寫CommitValue方法便可。事件
public HomePage() { this.InitializeComponent(); this.NavigationCacheMode = NavigationCacheMode.Required; } protected override void OnNavigatedFrom(NavigationEventArgs e) { base.OnNavigatedFrom(e); if (e.NavigationMode == NavigationMode.Back) { this.NavigationCacheMode = NavigationCacheMode.Disabled; } }
如何正確應用在MVVM模式中?使用Behavior!
<Button Content="圖片" Grid.Row="1"> <i:Interaction.Behaviors> <core:EventTriggerBehavior EventName="Click"> <behaviors:ShowListPickerAction ItemsSource="{Binding Images}" ItemTemplate="{ThemeResource ImageItemTemplate}" ItemsPickedCommand="{Binding ImagePickedCommand}" ItemsPickedInputConverter="{StaticResource ListPickerItemsPickedEventArgsConverter}"/> </core:EventTriggerBehavior> </i:Interaction.Behaviors> </Button>
轉載請註明出處。