简体   繁体   English

将ContentControl绑定到ApplicationViewModel将确定要查看哪个用户控件?

[英]Binding ContentControl to the ApplicationViewModel that will determine which user control to view?

I am very new to WPF and relatively new to C# programming (programming in general), and I'm trying to develop a WPF application. 我是WPF的新手,而C#编程(通常是编程)的新手,我正在尝试开发WPF应用程序。

I have tried to go through several posts similar to this, but I can't seem to find the answer of why this is not working. 我已经尝试过类似的几篇文章,但是我似乎找不到为什么不起作用的答案。

So, I'm having a hard time understanding the MVVM architecture, how and what it requires to switch between multiple user controls binded to a single <ContentControl /> . 因此,我很难理解MVVM体系结构,在绑定到单个<ContentControl />多个用户控件之间进行切换的方式和要求。 From what I understand and read so far, is that I have to bind the view model like this: 到目前为止,据我所了解和阅读的是,我必须像这样绑定视图模型:

<ContentControl Content="{Binding ApplicationViewModel}"/>

So here is what I want to a achieve: 所以这是我想要实现的目标:

An ApplicationWindow.xaml with sidebar menu on the left side that will be shown at all times when the application is running, and a <ContentControl/> on the remaining space. 一个ApplicationWindow.xaml带有在左侧的侧边栏菜单,在应用程序运行时将始终显示,并在剩余空间上显示<ContentControl/> Buttons shown on the sidebar menu will be: 侧栏菜单上显示的按钮为:

  • Main (will show MainView.xaml User Control, should be the default User Control) Main (将显示MainView.xaml用户控件,应为默认用户控件)
  • Settings (will show SettingsView.xaml User Control) 设置 (将显示SettingsView.xaml用户控件)
  • Exit (will close the application) 退出 (将关闭应用程序)

I understand that I need to bind the buttons to ICommand commands, and I understand the concept of a RelayCommand.cs class. 我知道我需要将按钮绑定到ICommand命令,并且我了解RelayCommand.cs类的概念。 So let's jump into the simplified code of my idea and figure out what I need to understand and what I may have misunderstood in the process. 因此,让我们进入我的想法的简化代码,弄清楚我需要了解的内容以及在过程中可能被误解的内容。

What MainView.xaml and SettingsView.xaml contain are not important right now, as I'm just trying to figure out how to show them in my application. MainView.xamlSettingsView.xaml包含的内容现在并不重要,因为我只是想弄清楚如何在应用程序中显示它们。

Here's the ApplicationWindow.xaml : 这是ApplicationWindow.xaml

<Window x:Class="WpfApp1.ApplicationWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        xmlns:v="clr-namespace:WpfApp1.View"
        xmlns:vm="clr-namespace:WpfApp1.ViewModel"
        mc:Ignorable="d"
        Title="ApplicationWindow" Height="1080" Width="1920"
        WindowStyle="None" WindowState="Maximized">

    <Window.Resources>
        <DataTemplate DataType="{x:Type vm:MainViewModel}">
            <v:MainView/>
        </DataTemplate>
        <DataTemplate DataType="{x:Type vm:SettingsViewModel}">
            <v:SettingsView/>
        </DataTemplate>
    </Window.Resources>

    <DockPanel>
        <!--Menu bar on the left-->
        <Border DockPanel.Dock="Left">
            <StackPanel Orientation="Vertical" Background="Gray" Width="120">
                <Button Content="Main" Command="{Binding ShowMainCommand}"/>
                <Button Content="Settings" Command="{Binding ShowSettingsCommand}"/>
                <Button Content="Exit" Command="{Binding ExitApplicationCommand}"/>
            </StackPanel>
        </Border>
        <!--The content control that view the current view-->
        <ContentControl Content="{Binding ApplicationViewModel}"/>
    </DockPanel>
</Window>

Note: DataContext is set to ApplicationViewModel.cs in App.xaml.cs by overriding the OnStartup() method. 注意:通过重写OnStartup()方法,将DataContext在App.xaml.cs中设置为ApplicationViewModel.cs

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        ApplicationWindow app = new ApplicationWindow
        {
            DataContext = new ApplicationViewModel()
        };
        app.Show();
    }
}

Here's the ApplicationViewModel.cs : 这是ApplicationViewModel.cs

public class ApplicationViewModel : ViewModelBase
{
    #region Fields

    private List<ViewModelBase> _viewModels;
    private ViewModelBase _currentViewModel;

    private ICommand _showMainCommand;
    private ICommand _showSettingsCommand;
    private ICommand _exitApplicationCommmand;

    #endregion

    #region Constructor

    public ApplicationViewModel()
    {
        ViewModels = new List<ViewModelBase>
        {
            new MainViewModel(),
            new SettingsViewModel()
        };

        CurrentViewModel = ViewModels[0];
    }

    #endregion

    #region Public Properties

    public List<ViewModelBase> ViewModels
    {
        get
        {
            return _viewModels;
        }
        set
        {
            if (_viewModels != value)
            {
                _viewModels = value;
                OnPropertyChanged(nameof(ViewModels));
            }
        }
    }

    public ViewModelBase CurrentViewModel
    {
        get
        {
            return _currentViewModel;
        }
        set
        {
            if(_currentViewModel != value)
            {
                _currentViewModel = value;
                OnPropertyChanged(nameof(CurrentViewModel));
            }
        }
    }

    #endregion

    #region Commands

    public ICommand ShowMainCommand
    {
        get
        {
            if(_showMainCommand == null)
            {
                _showMainCommand = new RelayCommand(action => ShowMain());
            }
            return _showMainCommand;
        }
    }

    public ICommand ShowSettingsCommand
    {
        get
        {
            if (_showSettingsCommand == null)
            {
                _showSettingsCommand = new RelayCommand(action => ShowSettings());
            }
            return _showSettingsCommand;
        }
    }

    public ICommand ExitApplicationCommand
    {
        get
        {
            if (_exitApplicationCommmand == null)
            {
                _exitApplicationCommmand = new RelayCommand(action => ExitApplication());
            }
            return _exitApplicationCommmand;
        }
    }

    #endregion

    #region Private Methods

    private void ShowMain()
    {
        CurrentViewModel = ViewModels[0];
    }

    private void ShowSettings()
    {
        CurrentViewModel = ViewModels[1];
    }

    private void ExitApplication()
    {
        MessageBoxResult result = MessageBox.Show("Are you sure you want to exit?", "Exit", MessageBoxButton.YesNo);
        if (result == MessageBoxResult.Yes)
        {
            System.Windows.Application.Current.Shutdown();
        }
    }

    #endregion
}

So, from what I understand, the ApplicationWindow.xaml should be able to determine which view to show out from what the CurrentViewModel is set to. 因此,据我了解, ApplicationWindow.xaml应该能够确定从CurrentViewModel设置为显示哪个视图。

For the sake of information (or miss-information), here are ViewModelBase.cs : 为了提供信息(或缺少信息),以下是ViewModelBase.cs

public class ViewModelBase : INotifyPropertyChanged
{
    #region INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion
}

And RelayCommand.cs : RelayCommand.cs

public class RelayCommand : ICommand
{
    #region Fields

    private readonly Action<object> _execute;
    private readonly Predicate<object> _canExecute;

    #endregion

    #region Constructors

    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");

        _execute = execute;
        _canExecute = canExecute;
    }

    public RelayCommand(Action<object> execute) : this(execute, null)
    {
    }

    #endregion

    #region ICommand

    public bool CanExecute(object parameters)
    {
        return _canExecute == null ? true : _canExecute(parameters);
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void Execute(object parameters)
    {
        _execute(parameters);
    }

    #endregion
}

I hope my thought process on this was clear to you, and that one of you smart programmers out there can help solving this, and help me understand why this isn't turning out as I want it to. 我希望我对这一点的思考过程对您很清楚,并且你们中的一位聪明的程序员可以帮助解决这个问题,并帮助我理解为什么这种情况没有达到我的期望。

In case of what I'm trying to do is harder than Elon Musk's project on making life multiplanetary, feel free to explain why and suggest me a better way to 如果我想做的事情比埃隆·马斯克(Elon Musk)的使生活成为多行星的项目更难,请随时解释原因,并向我建议一种更好的方法

您的Content控件绑定应指向您在切换ViewModels时更改的实际属性

<ContentControl Content="{Binding CurrentViewModel}"/>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM