簡體   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