如何在wpf mvvm中将现有页面导航到另一个页面



In windowMainwindow.xaml有一个

<Frame x:Name="Main" 
Source="/View/Home.xaml"
NavigationUIVisibility="Hidden"
DataContext="{StaticResource MainWindowVM}">
</Frame>

In pageHome.xamllistview

<ListView x:Name="ListViewStore" 
ItemsSource="{Binding ListStore}"
SelectionMode="Single"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Hidden">
<ListView.ItemTemplate>
<DataTemplate>
<!--2 textblocks that display StoreName and StoreAddress-->
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding StoreDetailCommand}"
CommandParameter="{Binding ElementName=Home}">         </i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListView>
在<<p> strong> HomeViewModel
public ICommand StoreDetailCommand { get; set; }
public HomeViewModel()
{
StoreDetailCommand = new RelayCommand<Home>((p) => { return p.ListViewStore.SelectedItem == null ? false : true; }, (p) => displayStoreDetail(p));
}
void displayStoreDetail(Home parameter)
{

}

当用户单击ListViewStore中的存储项时,页面StoreDetail.xaml主框架上显示的存储项相关的信息. 我如何导航和传递数据到StoreDetail.xaml?我很高兴有可能返回到以前的Home.xaml同时保持数据秩序。谢谢你花时间陪我。

我用谷歌搜索,但似乎没有想法

编辑:我在mainwindow . example .cs中创建静态实例,然后使用MainWindow.Instance.Main.NavigationService。导航(new Page()),它成功导航到新页面。我想知道每次我访问另一个视图中的元素:我应该创建一个新的静态实例吗?在这种情况下,我想学习良好的编码习惯。由于

注释有点长了,但进一步的解释似乎是明智的。

我链接到的文章对视图模型进行了简单的实例化。

在商业应用中你需要一些更复杂的东西,但是让我们忽略像依赖注入这样庞大的主题。

必须有一些东西实例化你的视图模型,这可能是最好的工厂处理,可以像lambda一样简单。

这大部分是航空代码,所以很抱歉拼写错误。这样做的目的是让你了解你需要做什么。这是相当广泛的。

在你的应用程序中,你会添加一个字典:

Dictionary<Type, Object> AllMyViewModels;

这将存储先前使用的视图模型的状态,这将反过来允许你存储用户最后在FooView中做的任何状态,因为你绑定了你关心的一切到FooViewModel。

让我们想象这是一个主窗口和一个单窗口应用程序。它有mainwindowviewmodel也许它包含ViewModels字典如果这是一个小应用

这是一个原型窗口。loginuc和useruc是用户控件。

Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate DataType="{x:Type local:LoginViewModel}">
<local:LoginUC/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:UserViewModel}">
<local:UserUC/>
</DataTemplate>
</Window.Resources>
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ItemsControl ItemsSource="{Binding NavigationViewModelTypes}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Name}"
Command="{Binding DataContext.NavigateCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
CommandParameter="{Binding VMType}"
/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<ContentPresenter Grid.Column="1"
Content="{Binding CurrentViewModel}"
/>
</Grid>
</Window>

单击itemscontrol中的其中一个按钮,将通过切换出CurrentViewModel来进行导航。它将被模板化为视图中的用户控件。

这是我碰巧拥有的一些代码,所以它可以很容易地通过使用社区mvvm工具包来改进。这只是给你(或任何人)一个想法。

MainWindowViewModel

public class MainWindowViewModel : INotifyPropertyChanged
{
public string MainWinVMString { get; set; } = "Hello from MainWindoViewModel";
public ObservableCollection<TypeAndDisplay> NavigationViewModelTypes { get; set; } = new ObservableCollection<TypeAndDisplay>
(
new List<TypeAndDisplay>
{
new TypeAndDisplay{ Name="Log In", VMType= typeof(LoginViewModel) },
new TypeAndDisplay{ Name="User", VMType= typeof(UserViewModel) }
}
);
private object currentViewModel;
public object CurrentViewModel
{
get { return currentViewModel; }
set { currentViewModel = value; RaisePropertyChanged(); }
}
private RelayCommand<Type> navigateCommand;
public RelayCommand<Type> NavigateCommand
{
get
{
return navigateCommand
?? (navigateCommand = new RelayCommand<Type>(
vmType =>
{
CurrentViewModel = null;
CurrentViewModel = Activator.CreateInstance(vmType);
}));
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}

实际上,type用于实例化不带任何参数的视图模型。这在上面的代码中每次都会发生。我们可以通过使用我们的字典来扩展它。

在添加

private Dictionary<Type, Object> viewModels = new Dictionary<Type, Object>();

并更改命令

?? (navigateCommand = new RelayCommand<Type>(
vmType =>
{
CurrentViewModel = null;
if (viewModels.ContainsKey(vmType))
{
CurrentViewModel = viewModels[vmType];
return;
}
CurrentViewModel = Activator.CreateInstance(vmType);
viewModels.Add(vmType, CurrentViewModel);
}));

现在,如果字典中没有视图模型,我们将其添加到字典中;如果有合适的视图模型,我们将返回字典中的内容。

你可以为每个传入参数的视图模型添加一个工厂。

其他可以改进的地方包括使用依赖注入。有些视图模型可能不想保留状态。当您注册视图模型并指定它们应该是单例还是瞬态(和新实例)时,您可以在依赖注入容器中进行区分。DI容器将替换字典。

通常,你想要的视图模型的参数是像仓库这样的服务,而这些服务又有你想要使用DI的依赖项。

最新更新