1.导航接口
public interface ICustomNavigationService
{
List<(string pageHostName, ApplicationPage page)> CurrentPageKeyList
{
get;
}
void GoBack(string pageHostName);
void NavigateTo(string pageHostName, ApplicationPage pageKey);
void NavigateTo(string pageHostName, ApplicationPage pageKey, object parameter);
}
2.实现
public class NavigationService : ICustomNavigationService
{
private object _navLock = new object();
private Dictionary<ApplicationPage, BasePage> _navigationDic;
private Dictionary<string, Stack<ApplicationPage>> _historyStack;
public List<(string pageHostName, ApplicationPage page)> CurrentPageKeyList { get; set; }
public NavigationService()
{
_navigationDic = new Dictionary<ApplicationPage, BasePage>();
_historyStack=new Dictionary<string, Stack<ApplicationPage>>();
CurrentPageKeyList = new List<(string, ApplicationPage)>();
}
public void GoBack(string pageHostName)
{
throw new NotImplementedException();
}
public void NavigateTo(string pageHostName, ApplicationPage pageKey)
{
NavigateTo(pageHostName, pageKey, null);
}
public void NavigateTo(string pageHostName, ApplicationPage pageKey, object parameter)
{
lock (_navLock)
{
if (!_navigationDic.ContainsKey(pageKey))
{
throw new ArgumentException("This key is not configured!");
}
List<PageHost> pageHosts = new List<PageHost>();
Application.Current.MainWindow.FindAllChilds<PageHost>(ref pageHosts);
var pageHost = pageHosts.FirstOrDefault(t => t.Name == pageHostName);
if (pageHost == null)
{
throw new Exception("PageHost is not Configured!");
}
if (!CurrentPageKeyList.Any(t => t.pageHostName == pageHostName))
{
CurrentPageKeyList.Add((pageHostName, pageKey));
_historyStack.Add(pageHostName, new Stack<ApplicationPage>());
}
else
{
_historyStack[pageHostName].Push(CurrentPageKeyList.First(t => t.pageHostName == pageHostName).page);
CurrentPageKeyList.Remove(CurrentPageKeyList.First(t => t.pageHostName == pageHostName));
CurrentPageKeyList.Add((pageHostName, pageKey));
}
var newPageFrame = pageHost.newPage;
var oldPageFrame = pageHost.oldPage;
var currentPageViewModel = pageHost.CurrentPageViewModel;
if (newPageFrame.Content is BasePage page && page == _navigationDic[pageKey])
page.ViewModelObject= currentPageViewModel;
var oldPageContent = newPageFrame.Content;
newPageFrame.Content = null;
oldPageFrame.Content = oldPageContent;
if (oldPageContent is BasePage oldPage)
{
oldPage.ShouldAnimateOut = true;
Task.Delay((int)(oldPage.SlideSeconds * 1000)).ContinueWith((t) =>
{
Application.Current.Dispatcher.Invoke(() => oldPageFrame.Content = null);
});
}
BasePage showPage = _navigationDic[pageKey];
showPage.ViewModelObject = currentPageViewModel;
showPage.ExtraData = parameter;
newPageFrame.Content = showPage;
}
}
public void Configure(ApplicationPage pageKey,BasePage basePage)
{
lock (_navLock)
{
if (_navigationDic.ContainsKey(pageKey))
{
throw new ArgumentException("This key is already used:"+pageKey);
}
if (_navigationDic.Values.Any(t => t == basePage))
{
throw new ArgumentException("This basepage is already configured with key "+ _navigationDic.First(t => t.Value == basePage).Key);
}
_navigationDic.Add(pageKey,basePage);
}
}
}
3.使用mvvmlight自定义viewmodel
public class BaseViewModel:ViewModelBase
{
protected object mPropertyValueCheckLock=new object();
protected async Task RunCommandAsync(Expression<Func<bool>> flagUpdating,Func<Task> action)
{
lock (mPropertyValueCheckLock)
{
if (flagUpdating.GetPropertyValue())
{
return;
}
flagUpdating.SetPropertyValue(true);
}
try
{
await action();
}
finally
{
flagUpdating.SetPropertyValue(false);
}
}
protected async Task<T> RunCommandAsync<T>(Expression<Func<bool>> flagUpdating, Func<Task<T>> action,T defaultValue)
{
lock (mPropertyValueCheckLock)
{
if (flagUpdating.GetPropertyValue())
{
return defaultValue;
}
flagUpdating.SetPropertyValue(true);
}
try
{
return await action();
}
finally
{
flagUpdating.SetPropertyValue(false);
}
}
}
public static class DependencyObjectHelpers
{
public static void FindAllChilds(this DependencyObject d, ref List<DependencyObject> dependencyObjects)
{
var count = VisualTreeHelper.GetChildrenCount(d);
for (int i = 0; i < count; i++)
{
DependencyObject dependencyObject = VisualTreeHelper.GetChild(d, i);
dependencyObjects.Add(dependencyObject);
FindAllChilds(dependencyObject, ref dependencyObjects);
}
}
public static void FindAllChilds<T>(this DependencyObject d, ref List<T> dependencyObjects) where T:class
{
var count = VisualTreeHelper.GetChildrenCount(d);
for (int i = 0; i < count; i++)
{
DependencyObject dependencyObject = VisualTreeHelper.GetChild(d, i);
if (dependencyObject.GetType() == typeof(T))
{
dependencyObjects.Add(dependencyObject as T);
}
FindAllChilds(dependencyObject, ref dependencyObjects);
}
}
}
public enum ApplicationPage
{
None=0
}
`public partial class PageHost : UserControl
{
public ApplicationPage CurrentPage
{
get { return (ApplicationPage)GetValue(CurrentPageProperty); }
set { SetValue(CurrentPageProperty, value); }
}
public static readonly DependencyProperty CurrentPageProperty =
DependencyProperty.Register("CurrentPage", typeof(ApplicationPage), typeof(PageHost), new PropertyMetadata(default(ApplicationPage),null, CurrentPagePropertyChanged));
public BaseViewModel CurrentPageViewModel
{
get { return (BaseViewModel)GetValue(CurrentPageViewModelProperty); }
set { SetValue(CurrentPageViewModelProperty, value); }
}
public static readonly DependencyProperty CurrentPageViewModelProperty =
DependencyProperty.Register("CurrentPageViewModel", typeof(BaseViewModel), typeof(PageHost), new PropertyMetadata(0));
public PageHost()
{
InitializeComponent();
if (DesignerProperties.GetIsInDesignMode(this))
newPage.Content = null;
}
private static object CurrentPagePropertyChanged(DependencyObject d, object value)
{
return value;
}
}
```csharp
public class BasePage : UserControl
{
#region Private Member
private object mViewModel;
#endregion
#region Public Properties
public PageAnimation PageLoadAnimation { get; set; } = PageAnimation.SlideAndFadeInFromRight;
public PageAnimation PageUnloadAnimation { get; set; } = PageAnimation.SlideAndFadeOutToLeft;
public float SlideSeconds { get; set; } = 0.4f;
public bool ShouldAnimateOut { get; set; }
public object ViewModelObject
{
get => mViewModel;
set
{
if (mViewModel == value)
return;
mViewModel = value;
OnViewModelChanged();
DataContext = mViewModel;
}
}
public object ExtraData { get; set; }
#endregion
#region Constructor
public BasePage()
{
if (DesignerProperties.GetIsInDesignMode(this))
return;
if (PageLoadAnimation != PageAnimation.None)
Visibility = Visibility.Collapsed;
Loaded += BasePage_LoadedAsync;
}
#endregion
#region Animation Load / Unload
private async void BasePage_LoadedAsync(object sender, System.Windows.RoutedEventArgs e)
{
if (ShouldAnimateOut)
await AnimateOutAsync();
else
await AnimateInAsync();
}
public async Task AnimateInAsync()
{
if (PageLoadAnimation == PageAnimation.None)
return;
switch (PageLoadAnimation)
{
case PageAnimation.SlideAndFadeInFromRight:
await this.SlideAndFadeInAsync(AnimationSlideInDirection.Right, false, SlideSeconds, size: (int)Application.Current.MainWindow.Width);
break;
}
}
public async Task AnimateOutAsync()
{
if (PageUnloadAnimation == PageAnimation.None)
return;
switch (PageUnloadAnimation)
{
case PageAnimation.SlideAndFadeOutToLeft:
await this.SlideAndFadeOutAsync(AnimationSlideInDirection.Left, SlideSeconds);
break;
}
}
#endregion
protected virtual void OnViewModelChanged()
{
}
}
public class BasePage<VM> : BasePage
where VM : BaseViewModel, new()
{
#region Public Properties
public VM ViewModel
{
get => (VM)ViewModelObject;
set => ViewModelObject = value;
}
#endregion
#region Constructor
public BasePage() : base()
{
if (DesignerProperties.GetIsInDesignMode(this))
ViewModel = new VM();
else
ViewModel = SimpleIoc.Default.GetInstance<VM>() ?? new VM();
}
public BasePage(VM specificViewModel = null) : base()
{
if (specificViewModel != null)
ViewModel = specificViewModel;
else
{
if (DesignerProperties.GetIsInDesignMode(this))
ViewModel = new VM();
else
{
ViewModel = SimpleIoc.Default.GetInstance<VM>() ?? new VM();
}
}
}
#endregion
}