繁体   English   中英

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

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

我是WPF的新手,而C#编程(通常是编程)的新手,我正在尝试开发WPF应用程序。

我已经尝试过类似的几篇文章,但是我似乎找不到为什么不起作用的答案。

因此,我很难理解MVVM体系结构,在绑定到单个<ContentControl />多个用户控件之间进行切换的方式和要求。 到目前为止,据我所了解和阅读的是,我必须像这样绑定视图模型:

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

所以这是我想要实现的目标:

一个ApplicationWindow.xaml带有在左侧的侧边栏菜单,在应用程序运行时将始终显示,并在剩余空间上显示<ContentControl/> 侧栏菜单上显示的按钮为:

  • Main (将显示MainView.xaml用户控件,应为默认用户控件)
  • 设置 (将显示SettingsView.xaml用户控件)
  • 退出 (将关闭应用程序)

我知道我需要将按钮绑定到ICommand命令,并且我了解RelayCommand.cs类的概念。 因此,让我们进入我的想法的简化代码,弄清楚我需要了解的内容以及在过程中可能被误解的内容。

MainView.xamlSettingsView.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>

注意:通过重写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();
    }
}

这是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
}

因此,据我了解, ApplicationWindow.xaml应该能够确定从CurrentViewModel设置为显示哪个视图。

为了提供信息(或缺少信息),以下是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
}

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
}

我希望我对这一点的思考过程对您很清楚,并且你们中的一位聪明的程序员可以帮助解决这个问题,并帮助我理解为什么这种情况没有达到我的期望。

如果我想做的事情比埃隆·马斯克(Elon Musk)的使生活成为多行星的项目更难,请随时解释原因,并向我建议一种更好的方法

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

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

暂无
暂无

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

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