UWP NavigationView 通过 MVVM 切换到另一个页面
UWP NavigationView switch to another page via MVVM
第一次从 WPF 切换到 UWP,我发现 UWP 的世界中确实存在像 SplitView
和 NavgiationView
这样很棒的控件。
为了更新我当前的家庭项目,我选择 NavigationView
控件作为我的主要 UI 控件来提供各种信息。
使用页面导航 (as shown here) 的代码隐藏非常简单,但对于我的用例,我想使用 MVVM(作为一个学习过程,不使用像 MVVMLIght 或类似的固件)。
目前,我的 NavigationView
看起来像这样;但我不知道如何通过页面在框架内进行更改(根据我的理解,我必须使用 NavigationService
但还没有找到一个易于理解的示例):
<NavigationView x:Name="nvTopLevelNav" Grid.Column="0" Grid.Row="1" Grid.RowSpan="3" IsPaneOpen="False" IsPaneToggleButtonVisible="False" CompactModeThresholdWidth="0" IsBackButtonVisible="Collapsed" Background="Black" Foreground="Black"
Loaded="nvTopLevelNav_Loaded"
Margin="0,12,0,0"
SelectionChanged="nvTopLevelNav_SelectionChanged"
ItemInvoked="nvTopLevelNav_ItemInvoked"
IsTabStop="False"
IsSettingsVisible="False"
AlwaysShowHeader="False"
Header="asdasdaasdasdasd">
<NavigationView.MenuItems>
<NavigationViewItem Icon="Home" Content="Home" Tag="Home_Page" />
<NavigationViewItem Icon="Globe" Content="Weather" Tag="Weather_Page" />
<NavigationViewItem Content="My Agenda" Tag="Agenda_Page">
<!-- some custom PathIcon -->
</NavigationViewItem>
<NavigationViewItem Icon="Contact" Content="My News" Tag="News_Page" />
</NavigationView.MenuItems>
<Frame x:Name="contentFrame"></Frame>
</NavigationView>
UWP NavigationView switch to another page via MVVM
根据您的要求,您可以使用 Windows Template Studio
创建包含 MVVM 模式和 NavigationService
的 UWP 项目。
private void OnItemInvoked(NavigationViewItemInvokedEventArgs args)
{
if (args.IsSettingsInvoked)
{
NavigationService.Navigate(typeof(SettingsViewModel).FullName);
return;
}
var item = _navigationView.MenuItems
.OfType<NavigationViewItem>()
.First(menuItem => (string)menuItem.Content == (string)args.InvokedItem);
var pageKey = item.GetValue(NavHelper.NavigateToProperty) as string;
NavigationService.Navigate(pageKey);
}
阅读我的博客,了解我在没有任何第 3 方的情况下提出的解决方案 api,还有 github 解决方案报告。
https://kwodarczyk.github.io/UwpWinUI3PageMVVMNavigation/
所有你需要的附件属性允许将视图模型类型传递给你的数据模板
public class ViewModelContext : DependencyObject
{
public static readonly DependencyProperty TypeProperty =
DependencyProperty.RegisterAttached(
"ViewModelContext",
typeof(Type),
typeof(ViewModelContext),
new PropertyMetadata(null)
);
public static void SetType(DependencyObject element, Type value)
{
element.SetValue(TypeProperty, value);
}
public static Type GetType(DependencyObject element)
{
return (Type)element.GetValue(TypeProperty);
}
}
示例数据模板:
<DataTemplate x:Key="PageOne" viewModels:ViewModelContext.Type="viewModels:PageOneViewModel">
<views:PageOne/>
</DataTemplate>
和自定义模板选择器,您可以在其中将模板与视图模型相匹配
public class CustomTemplateSelector : DataTemplateSelector
{
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
if (item != null)
{
var viewModeltype = item.GetType();
foreach (var rd in Application.Current.Resources.MergedDictionaries)
{
foreach (var value in rd.Values)
{
if (value is DataTemplate dataTempate)
{
Type contexType = dataTempate.GetValue(ViewModelContext.TypeProperty) as Type;
if (contexType != null && contexType == viewModeltype)
{
return dataTempate;
}
}
}
}
}
return null;
}
}
第一次从 WPF 切换到 UWP,我发现 UWP 的世界中确实存在像 SplitView
和 NavgiationView
这样很棒的控件。
为了更新我当前的家庭项目,我选择 NavigationView
控件作为我的主要 UI 控件来提供各种信息。
使用页面导航 (as shown here) 的代码隐藏非常简单,但对于我的用例,我想使用 MVVM(作为一个学习过程,不使用像 MVVMLIght 或类似的固件)。
目前,我的 NavigationView
看起来像这样;但我不知道如何通过页面在框架内进行更改(根据我的理解,我必须使用 NavigationService
但还没有找到一个易于理解的示例):
<NavigationView x:Name="nvTopLevelNav" Grid.Column="0" Grid.Row="1" Grid.RowSpan="3" IsPaneOpen="False" IsPaneToggleButtonVisible="False" CompactModeThresholdWidth="0" IsBackButtonVisible="Collapsed" Background="Black" Foreground="Black"
Loaded="nvTopLevelNav_Loaded"
Margin="0,12,0,0"
SelectionChanged="nvTopLevelNav_SelectionChanged"
ItemInvoked="nvTopLevelNav_ItemInvoked"
IsTabStop="False"
IsSettingsVisible="False"
AlwaysShowHeader="False"
Header="asdasdaasdasdasd">
<NavigationView.MenuItems>
<NavigationViewItem Icon="Home" Content="Home" Tag="Home_Page" />
<NavigationViewItem Icon="Globe" Content="Weather" Tag="Weather_Page" />
<NavigationViewItem Content="My Agenda" Tag="Agenda_Page">
<!-- some custom PathIcon -->
</NavigationViewItem>
<NavigationViewItem Icon="Contact" Content="My News" Tag="News_Page" />
</NavigationView.MenuItems>
<Frame x:Name="contentFrame"></Frame>
</NavigationView>
UWP NavigationView switch to another page via MVVM
根据您的要求,您可以使用 Windows Template Studio
创建包含 MVVM 模式和 NavigationService
的 UWP 项目。
private void OnItemInvoked(NavigationViewItemInvokedEventArgs args)
{
if (args.IsSettingsInvoked)
{
NavigationService.Navigate(typeof(SettingsViewModel).FullName);
return;
}
var item = _navigationView.MenuItems
.OfType<NavigationViewItem>()
.First(menuItem => (string)menuItem.Content == (string)args.InvokedItem);
var pageKey = item.GetValue(NavHelper.NavigateToProperty) as string;
NavigationService.Navigate(pageKey);
}
阅读我的博客,了解我在没有任何第 3 方的情况下提出的解决方案 api,还有 github 解决方案报告。
https://kwodarczyk.github.io/UwpWinUI3PageMVVMNavigation/
所有你需要的附件属性允许将视图模型类型传递给你的数据模板
public class ViewModelContext : DependencyObject
{
public static readonly DependencyProperty TypeProperty =
DependencyProperty.RegisterAttached(
"ViewModelContext",
typeof(Type),
typeof(ViewModelContext),
new PropertyMetadata(null)
);
public static void SetType(DependencyObject element, Type value)
{
element.SetValue(TypeProperty, value);
}
public static Type GetType(DependencyObject element)
{
return (Type)element.GetValue(TypeProperty);
}
}
示例数据模板:
<DataTemplate x:Key="PageOne" viewModels:ViewModelContext.Type="viewModels:PageOneViewModel">
<views:PageOne/>
</DataTemplate>
和自定义模板选择器,您可以在其中将模板与视图模型相匹配
public class CustomTemplateSelector : DataTemplateSelector
{
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
if (item != null)
{
var viewModeltype = item.GetType();
foreach (var rd in Application.Current.Resources.MergedDictionaries)
{
foreach (var value in rd.Values)
{
if (value is DataTemplate dataTempate)
{
Type contexType = dataTempate.GetValue(ViewModelContext.TypeProperty) as Type;
if (contexType != null && contexType == viewModeltype)
{
return dataTempate;
}
}
}
}
}
return null;
}
}