C# MVVM导航父视图和子视图
我有一个GeneralView,它是一个父视图,当打开它时,会打开父视图,后面跟着一个子视图。我想实现导航,并将按钮放在旁边(像一个用户页面)。让我们转到所需的行为,然后是我现在拥有的代码 我如何实现ChildView不改变,停留在HomeView又名FriendsView中 因此,description Login>GeneralView(在家中立即打开)>单击About,子视图将更改为AboutView,单击Home再次显示Home视图 我所拥有的: 通用视图C# MVVM导航父视图和子视图,c#,wpf,xaml,mvvm,navigation,C#,Wpf,Xaml,Mvvm,Navigation,我有一个GeneralView,它是一个父视图,当打开它时,会打开父视图,后面跟着一个子视图。我想实现导航,并将按钮放在旁边(像一个用户页面)。让我们转到所需的行为,然后是我现在拥有的代码 我如何实现ChildView不改变,停留在HomeView又名FriendsView中 因此,description Login>GeneralView(在家中立即打开)>单击About,子视图将更改为AboutView,单击Home再次显示Home视图 我所拥有的: 通用视图 <UserContro
<UserControl x:Class="WpfWHERE.View.GeneralView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfWHERE.View"
xmlns:ViewModel="clr-namespace:WpfWHERE.ViewModel"
mc:Ignorable="d"
d:DesignHeight="600" d:DesignWidth="800">
<UserControl.DataContext>
<ViewModel:GeneralViewModel/>
</UserControl.DataContext>
<UserControl.Resources>
<DataTemplate DataType="{x:Type ViewModel:FriendsViewModel}">
<local:FriendsView />
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModel:AboutViewModel}">
<local:AboutView />
</DataTemplate>
</UserControl.Resources>
<DockPanel Margin="0,0,0,0">
<StackPanel Orientation="Horizontal">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MaxWidth="200"/>
</Grid.ColumnDefinitions>
<Image Grid.Column="1" x:Name="userImage" Source="/Resources/Images/profileImage.png" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Height="161" Width="180" />
<Label Grid.Column="1" x:Name="labelName" Content="NameHere" HorizontalAlignment="Left" Margin="10.4,171,0,0" VerticalAlignment="Top" RenderTransformOrigin="0.536,1.344" Height="26" Width="67"/>
<StackPanel Grid.Column="1" Margin="0.4,202,-1.2,0" VerticalAlignment="Top" Height="200">
<MenuItem Style="{DynamicResource MyMenuItem}" Command="{Binding DataContext.SelectViewCommand, ElementName=GeneralView}" CommandParameter="FriendsViewModel" Header="Home" x:Name="Home"/>
<MenuItem Style="{DynamicResource MyMenuItem}" Header="Overview" x:Name="Overview"/>
<MenuItem Style="{DynamicResource MyMenuItem}" Header="Settings" x:Name="Settings"/>
<MenuItem Style="{DynamicResource MyMenuItem}" Header="About" Command="{Binding DataContext.SelectViewCommand, ElementName=GeneralView}" CommandParameter="AboutViewModel" x:Name="About"/>
</StackPanel>
</Grid>
<ContentControl Content="{Binding Current_ViewModel}" Height="600" Width="600"/>
</StackPanel>
</DockPanel>
AViewModel接口
public abstract class AViewModel : ViewModelBase
{
public string Name { get; set; }
public RelayCommand<string> SelectViewCommand { get; set; }
public AViewModel()
{
SelectViewCommand = new RelayCommand<string>(OnSelectViewCommand);
}
private static ObservableCollection<ViewModelBase> _ViewModels;
public static ObservableCollection<ViewModelBase> ViewModels
{
get { return _ViewModels; }
set { _ViewModels = value; }
}
public void AddViewModel(ViewModelBase viewmodel)
{
if (ViewModels == null)
ViewModels = new ObservableCollection<ViewModelBase>();
if (!ViewModels.Contains(viewmodel))
ViewModels.Add(viewmodel);
}
public ViewModelBase GetViewModel(string viewmodel)
{
return ViewModels.FirstOrDefault(item => item.InternalName == viewmodel);
}
private void OnSelectViewCommand(string obj)
{
switch (obj)
{
case "ExitCommand":
Application.Current.Shutdown();
break;
default:
this.Current_ViewModel = this.GetViewModel(obj);
break;
}
}
private ViewModelBase _Current_ViewModel;
public ViewModelBase Current_ViewModel
{
get { return _Current_ViewModel; }
set { _Current_ViewModel = value; OnPropertyChanged("Current_ViewModel"); }
}
}
公共抽象类AViewModel:ViewModelBase
{
公共字符串名称{get;set;}
public RelayCommand selectview命令{get;set;}
公共航空模型()
{
选择VIEWCOMMAND=new RelayCommand(打开选择VIEWCOMMAND);
}
私有静态ObservableCollection _ViewModels;
公共静态ObservableCollection视图模型
{
获取{return\u ViewModels;}
设置{u ViewModels=value;}
}
public void AddViewModel(ViewModelBase viewmodel)
{
if(ViewModels==null)
ViewModels=新的ObservableCollection();
如果(!ViewModels.Contains(viewmodel))
添加(viewmodel);
}
公共ViewModelBase GetViewModel(字符串viewmodel)
{
返回ViewModels.FirstOrDefault(item=>item.InternalName==viewmodel);
}
私有void onselectview命令(字符串obj)
{
开关(obj)
{
案例“ExitCommand”:
Application.Current.Shutdown();
打破
违约:
this.Current_ViewModel=this.GetViewModel(obj);
打破
}
}
私有ViewModelBase\u当前\u ViewModel;
公共视图模型库当前_视图模型
{
获取{return\u Current\u ViewModel;}
设置{当前视图模型=值;OnPropertyChanged(“当前视图模型”);}
}
}
试试这个
改变这个
<StackPanel Grid.Column="1" Margin="0.4,202,-1.2,0" VerticalAlignment="Top" Height="200">
<MenuItem Style="{DynamicResource MyMenuItem}" Command="{Binding DataContext.SelectViewCommand, ElementName=GeneralView}" CommandParameter="FriendsViewModel" Header="Home" x:Name="Home"/>
<MenuItem Style="{DynamicResource MyMenuItem}" Header="Overview" x:Name="Overview"/>
<MenuItem Style="{DynamicResource MyMenuItem}" Header="Settings" x:Name="Settings"/>
<MenuItem Style="{DynamicResource MyMenuItem}" Header="About" Command="{Binding DataContext.SelectViewCommand, ElementName=GeneralView}" CommandParameter="AboutViewModel" x:Name="About"/>
</StackPanel>
这里我在Base_V中调用selectview命令,这是因为我想更改Base_V的ContentControl中显示的视图
在主视图中,我调用
Command="{Binding SelectViewCommand}", CommandParameter="MainV1_ViewModel"
在这里,我调用Main_ViewModel中的selectview命令,这是因为我想更改ManiView的ContentControl中显示的视图
对于任何想要我上面提到的演示代码的人,你可以在这里找到它
另外,对代码进行一点更新。。。将AviewModel中的AddViewModel函数替换为
public void AddViewModel(ViewModelBase viewmodel)
{
if (ViewModels == null)
ViewModels = new ObservableCollection<ViewModelBase>();
var currentVNs = (from vms in ViewModels where vms.InternalName == viewmodel.InternalName select vms).FirstOrDefault();
if (currentVNs == null)
ViewModels.Add(viewmodel);
}
public void AddViewModel(ViewModelBase viewmodel)
{
if(ViewModels==null)
ViewModels=新的ObservableCollection();
var currentVNs=(来自ViewModels中的虚拟机,其中vms.InternalName==viewmodel.InternalName选择虚拟机);
if(currentVNs==null)
添加(viewmodel);
}
试试这个
改变这个
<StackPanel Grid.Column="1" Margin="0.4,202,-1.2,0" VerticalAlignment="Top" Height="200">
<MenuItem Style="{DynamicResource MyMenuItem}" Command="{Binding DataContext.SelectViewCommand, ElementName=GeneralView}" CommandParameter="FriendsViewModel" Header="Home" x:Name="Home"/>
<MenuItem Style="{DynamicResource MyMenuItem}" Header="Overview" x:Name="Overview"/>
<MenuItem Style="{DynamicResource MyMenuItem}" Header="Settings" x:Name="Settings"/>
<MenuItem Style="{DynamicResource MyMenuItem}" Header="About" Command="{Binding DataContext.SelectViewCommand, ElementName=GeneralView}" CommandParameter="AboutViewModel" x:Name="About"/>
</StackPanel>
这里我在Base_V中调用selectview命令,这是因为我想更改Base_V的ContentControl中显示的视图
在主视图中,我调用
Command="{Binding SelectViewCommand}", CommandParameter="MainV1_ViewModel"
在这里,我调用Main_ViewModel中的selectview命令,这是因为我想更改ManiView的ContentControl中显示的视图
对于任何想要我上面提到的演示代码的人,你可以在这里找到它
另外,对代码进行一点更新。。。将AviewModel中的AddViewModel函数替换为
public void AddViewModel(ViewModelBase viewmodel)
{
if (ViewModels == null)
ViewModels = new ObservableCollection<ViewModelBase>();
var currentVNs = (from vms in ViewModels where vms.InternalName == viewmodel.InternalName select vms).FirstOrDefault();
if (currentVNs == null)
ViewModels.Add(viewmodel);
}
public void AddViewModel(ViewModelBase viewmodel)
{
if(ViewModels==null)
ViewModels=新的ObservableCollection();
var currentVNs=(来自ViewModels中的虚拟机,其中vms.InternalName==viewmodel.InternalName选择虚拟机);
if(currentVNs==null)
添加(viewmodel);
}
好的,所以。。。再想一想。。。。互联网上很多教程代码的问题在于它非常基本。数据(模型)视图之间关系的实现,似乎是一个品味问题。然而,我只见过它做得不好。就我个人而言,我所研究的大多数WPF应用程序都是绝对垃圾、无法维护和无法管理的意大利面代码……你可以清楚地看到,最初的开发人员在开发过程中已经“学会了”,一切都无处不在,没有一致性。。。。正如我通常在项目进行到一半时所做的那样,尽管我别无选择,只能继续它已经开始的方式,所以我从来没有对它进行过多的思考,直到现在
我自己的理解是,“模型”定义了数据结构,“视图”向用户显示数据,“视图模型”是将数据(模型)转换为可向用户显示的内容的中间位置
在ViewModel中,您只需拥有可观的集合(数据列表(模型))和单个数据实例(模型的单个实例)。“视图”然后绑定到ObservableCollections(和单个模型实例)以显示该数据(使用XAML和模板等的魔力)
至于将对象(类)传递给ViewModel,我认为实际上不需要这样做。您只需在ViewModel中创建一个表示要显示的数据的属性,然后在需要时从“源”检索数据(通常在显示视图时,但也可以是计时器线程或其他对象上的周期性数据)
我的演示代码(下载)的主要问题是,在应用程序启动后从未调用ViewModels的构造函数,因此无法从数据源刷新ViewModel中的属性
也许有更好的方法可以做到这一点,但我已经通过在“ViewModelBase”中引入名为Initialize的事件解决了这个问题
public delegate void MyEventHadler();
public event MyEventHadler Initialize;
public void InitializeFunction()
{
if (Initialize != null)
Initialize.Invoke();
}
public MainV2_ViewModel()
{
this.Initialize += MainV2_ViewModel_Initialize; // our new Event
}
private void MainV2_ViewModel_Initialize()
{
// So here we are retrieving a List of All users from the WCF Service
this.AllUsers = new ObservableCollection<ServiceReference1.User>( DataAccessLevel.sr1.GetAllUsers());
// Now our AllUsers property has been updated and the View will display the new data
}
private ViewModelBase _Current_ViewModel;
public ViewModelBase Current_ViewModel
{
get { return _Current_ViewModel; }
set {
_Current_ViewModel = value;
// the Constructor of the ViewModel never gets called more that once on App Start
// so we have to implement/raise our own event when changing from one View to another.
if (Current_ViewModel != null)
Current_ViewModel.InitializeFunction(); // InitializeFunction will fire the event in this ViewModel, we can now initialise the properties.
OnPropertyChanged("Current_ViewModel"); }
}