从用户控件内部更改视图

时间:2019-07-05 08:21:55

标签: c# wpf mvvm

我的想法是要有一个窗口,其中2个内容控件会更改为不同的视图。例如,我的应用可能从一个内容控件中的欢迎图像开始,而在另一个内容控件中进入/退出按钮。单击输入按钮时,我要将欢迎视图更改为其他视图,并将输入/退出按钮更改为其他3个按钮。

我当前的问题是,如果我将其放入用户控件并将其托管在内容控件中,则试图通过单击Enter按钮来更改欢迎视图似乎不起作用。我的猜测是因为我实际上是在创建MainViewModel的新实例,而不是引用现有实例,但是我不确定。

当我在BottomPanelTwoButtonsView中单击按钮时,如何将HomeView更改为TestView

共有4个视图:

HomeView-欢迎屏幕

TestView-其他视图

BottomPanelTwoButtonsView-进入/退出按钮

BottomPanelThreeButtonsView-其他3个按钮

这是我的基本代码:

App.xaml.cs

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

            MainWindow app = new MainWindow();
            MainViewModel context = new MainViewModel();
            app.DataContext = context;
            app.Show();
        }
    }

MainWindow.xaml

<Window x:Class="MyApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:localViewModels="clr-namespace:MyApp.ViewModels"
        xmlns:localViews="clr-namespace:MyApp.Views"
        mc:Ignorable="d"
        Name="RootWindow"
        WindowStyle="None" ResizeMode="NoResize"
        Topmost="True"
        WindowStartupLocation="CenterScreen"
        WindowState="Maximized"
        Background="{StaticResource BackgroundSolidColorBrush}"
        ToolBarTray.IsLocked="True"
        NumberSubstitution.Substitution="European"
        Title="MyApp" Height="1920" Width="1080">
    <Window.Resources>
        <DataTemplate DataType="{x:Type localViewModels:HomeViewModel}">
            <localViews:HomeView />
        </DataTemplate>
        <DataTemplate DataType="{x:Type localViewModels:TestViewModel}">
            <localViews:TestView />
        </DataTemplate>
        <DataTemplate DataType="{x:Type localViewModels:BottomPanelTwoButtonsViewModel}">
            <localViews:BottomPanelTwoButtons />
        </DataTemplate>
        <DataTemplate DataType="{x:Type localViewModels:BottomPanelThreeButtonsViewModel}">
            <localViews:BottomPanelThreeButtons />
        </DataTemplate>
    </Window.Resources>
    <DockPanel Background="White">           
        <ContentControl Content="{Binding CurrentBottomPanelViewModel}" DockPanel.Dock="Bottom" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" Height="96" Width="1080">                
        </ContentControl>
        <ContentControl Content="{Binding CurrentPageViewModel}" HorizontalAlignment="Stretch" VerticalAlignment="Top" HorizontalContentAlignment="Stretch" Height="1824" Width="1080">               
        </ContentControl>
    </DockPanel>
</Window>

MainViewModel.cs

public class MainViewModel : ObservableObject
    {
        #region Fields

        private ICommand _changePageCommand;
        private IPageViewModel _currentPageViewModel;
        private IBottomPanelViewModel _currentBottomPanelViewModel;
        private ObservableCollection<IPageViewModel> _pageViewModels;

        #endregion

        public MainViewModel()
        {

            CurrentPageViewModel = new HomeViewModel();
            CurrentBottomPanelViewModel = new BottomPanelTwoButtonsViewModel();
            //CurrentBottomPanelViewModel = new BottomPanelThreeButtonsViewModel();

            PageViewModels.Add(new ScreeningsScheduleViewModel());
            PageViewModels.Add(new TestViewModel());
            PageViewModels.Add(CurrentPageViewModel);
        }

        #region Properties / Commands

        public ICommand ChangePageCommand
        {
            get
            {
                if (_changePageCommand == null)
                {
                    _changePageCommand = new RelayCommand(
                        p => ChangeViewModel((IPageViewModel)p),
                        p => p is IPageViewModel);
                }

                return _changePageCommand;
            }
        }

        public ObservableCollection<IPageViewModel> PageViewModels
        {
            get
            {
                if (_pageViewModels == null)
                {
                    _pageViewModels = new ObservableCollection<IPageViewModel>();
                }

                return _pageViewModels;
            }
            set
            {
                _pageViewModels = value;
                OnPropertyChanged("PageViewModels");
            }
        }

        public IPageViewModel CurrentPageViewModel
        {
            get => _currentPageViewModel;
            set
            {
                if (_currentPageViewModel != value)
                {
                    _currentPageViewModel = value;
                    OnPropertyChanged("CurrentPageViewModel");
                }
            }
        }

        public IBottomPanelViewModel CurrentBottomPanelViewModel
        {
            get => _currentBottomPanelViewModel;
            set
            {
                if (_currentBottomPanelViewModel != value)
                {
                    _currentBottomPanelViewModel = value;
                    OnPropertyChanged("CurrentBottomPanelViewModel");
                }
            }
        }

        #endregion

        #region Methods

        private void ChangeViewModel(IPageViewModel viewModel)
        {                
            if (!PageViewModels.Contains(viewModel))
            {
                PageViewModels.Add(viewModel);
            }

            CurrentPageViewModel = PageViewModels
                .FirstOrDefault(vm => vm == viewModel);    
        }

        #endregion
    }

BottomPanelTwoButtonsView.xaml

<UserControl x:Class="MyApp.Views.BottomPanelTwoButtons"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:mvm="clr-namespace:MyApp"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="1080">
    <UserControl.DataContext>
        <mvm:MainViewModel/>
    </UserControl.DataContext>
    <Grid Height="96" Background="White" Width="1080">
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Button Grid.Column="0" 
                Content="1"
                Command="{Binding DataContext.ChangePageCommand, Source={RelativeSource Mode=FindAncestor, AncestorType={x:Type mvm:MainViewModel}}, Mode=TwoWay}"
                CommandParameter="{Binding PageViewModels[2]}"
                IsEnabled="True"
                Style="{StaticResource RoundCornerButtonCyanFilledBig}" 
                />
        <Button Grid.Column="1" Style="{StaticResource RoundCornerButtonMagentaFilledBig}"/>
    </Grid>
</UserControl>

IPageViewModel.cs

public interface IPageViewModel
    {
        string Name { get; }
    }

ObservableObject.cs

public abstract class ObservableObject : INotifyPropertyChanged
    {
        [Conditional("DEBUG")]
        [DebuggerStepThrough]
        public virtual void VerifyPropertyName(string propertyName)
        {        
            if (TypeDescriptor.GetProperties(this)[propertyName] == null)
            {
                string msg = "Invalid property name: " + propertyName;

                if (!ThrowOnInvalidPropertyName)
                {
                    Debug.Fail(msg);
                }
                else
                {
                    throw new Exception(msg);
                }
            }
        }

        protected virtual bool ThrowOnInvalidPropertyName { get; private set; }

        public virtual void RaisePropertyChanged(string propertyName)
        {
            VerifyPropertyName(propertyName);
            OnPropertyChanged(propertyName);
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            this.VerifyPropertyName(propertyName);

            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null)
            {
                var e = new PropertyChangedEventArgs(propertyName);
                handler(this, e);
            }
        }
    }

RelayCommand.cs

public class RelayCommand : ICommand
    {
        readonly Action<object> _execute;
        readonly Predicate<object> _canExecute;

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

        public RelayCommand(Action<object> execute, Predicate<object> canExecute)
        {
            _execute = execute ?? throw new ArgumentNullException("execute");
            _canExecute = canExecute;
        }

        [DebuggerStepThrough]
        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);
        }
    }

1 个答案:

答案 0 :(得分:0)

我想您的问题出在BottomPanelTwoButtonsView.xaml

您有以下几行:

<UserControl.DataContext>
    <mvm:MainViewModel/>
</UserControl.DataContext>

因此,您要覆盖Window中定义的数据上下文。MainWindow的资源