Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/267.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# MVVM导航父视图和子视图_C#_Wpf_Xaml_Mvvm_Navigation - Fatal编程技术网

C# MVVM导航父视图和子视图

C# MVVM导航父视图和子视图,c#,wpf,xaml,mvvm,navigation,C#,Wpf,Xaml,Mvvm,Navigation,我有一个GeneralView,它是一个父视图,当打开它时,会打开父视图,后面跟着一个子视图。我想实现导航,并将按钮放在旁边(像一个用户页面)。让我们转到所需的行为,然后是我现在拥有的代码 我如何实现ChildView不改变,停留在HomeView又名FriendsView中 因此,description Login>GeneralView(在家中立即打开)>单击About,子视图将更改为AboutView,单击Home再次显示Home视图 我所拥有的: 通用视图 <UserContro

我有一个GeneralView,它是一个父视图,当打开它时,会打开父视图,后面跟着一个子视图。我想实现导航,并将按钮放在旁边(像一个用户页面)。让我们转到所需的行为,然后是我现在拥有的代码

我如何实现ChildView不改变,停留在HomeView又名FriendsView中

因此,description Login>GeneralView(在家中立即打开)>单击About,子视图将更改为AboutView,单击Home再次显示Home视图

我所拥有的:

通用视图

<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"); }
    }