简体   繁体   English

MVVM WPF - 更改视图会创建新的视图实例

[英]MVVM WPF - Changing Views creates new Instances of View

I've decided to move away from WinForms as I wanted to be more flexible in creating my UIs.我决定放弃 WinForms,因为我想更灵活地创建我的 UI。 That said I'm just starting with WPF and the MVVM structure.也就是说,我只是从 WPF 和 MVVM 结构开始。 I'm having a blast learning all the new stuff and trying to learn the "best practices" right away.我正在愉快地学习所有新东西并立即尝试学习“最佳实践”。

One thing I'm wondering is that with my current implementation of MVVM and navigation through my views it would always create a new instance of the View when changing my CurrentView of my MainViewModel of my MainWindow .我想知道的一件事是,在我当前实现的 MVVM 和通过我的视图导航的情况下,当更改我的MainWindowMainViewModelCurrentView时,它总是会创建一个新的 View 实例。

Is that the intended way?那是预期的方式吗? As I notice quite a bit of lagging when changing them which feels... wrong?正如我注意到在更改它们时感觉有点滞后......错误? As a sidenote I'm currently not on my normal workstation but on a older surface which is getting stressed easily with VS running etc作为旁注,我目前不在我的普通工作站上,而是在一个较旧的表面上,它很容易因 VS 运行等而受到压力

A pretty 'standard' MainViewModel一个漂亮的“标准”MainViewModel

    public class MainViewModel : ObservableObject
    {

        public MainViewModel()
        {
            this.PageViewModels.Add(new EventsViewModel());
            this.PageViewModels.Add(new SettingsViewModel());
            this.PageViewModels.Add(new AnotherViewModel());

            this.CurrentView = this.PageViewModels[0];
        }

        public ViewModelBase CurrentView
        {
            get
            {
                return this._currentVIew;
            }

            set
            {
                this._currentVIew = value;
                this.OnPropertyChanged("CurrentView");
            }
        }


        public ICommand ChangePageCommand
        {
            get
            {
                if (this.changePageCommand == null)
                {
                    this.changePageCommand = new RelayCommand(
                        p => this.ChangeViewModel(p),
                        p => true);
                }

                return this.changePageCommand;
            }
        }

        private void ChangeViewModel(object viewModel)
        {
            var t = (Type)viewModel;
            foreach (var v in this.PageViewModels)
            {
                if (v.GetType() == t)
                {
                    this.CurrentView = v;
                    return;
                }
            }
        }
}

'Normal' View Data Templating “正常”视图数据模板

            <DataTemplate DataType="{x:Type viewModel:EventsViewModel}">
                <view:EventView/>
            </DataTemplate>
            
            <DataTemplate DataType="{x:Type viewModel:SettingsViewModel}">
                <view:SettingsView/>
            </DataTemplate>
            
            <DataTemplate DataType="{x:Type viewModel:AnotherViewModel}">
                <view:AnotherView/>
            </DataTemplate>

The way the Command is beeing called, just with different x:Type parameter调用命令的方式,只是使用不同的x:Type参数

Command="{Binding DataContext.ChangePageCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"
CommandParameter="{x:Type viewModel:SettingsViewModel}"      

First on the general theory.首先是一般理论。 All "MV*" patterns separate the functionality of the View and Model into different layers.所有“MV*”模式将 View 和 Model 的功能分成不同的层。 An additional third layer (Controler, Presenter, ViewModel, etc.) performs the function of matching between the Model and the View.附加的第三层(Controler、Presenter、ViewModel 等)执行 Model 和 View 之间的匹配 function。 Therefore, it is meaningless to consider View and ViewMode in isolation.因此,孤立地考虑View和ViewMode是没有意义的。 VM is (in fact) a proxy reflecting the Model in its properties. VM(实际上)是一个在其属性中反映 Model 的代理。 A common mistake is when ANY Data Context is called a ViewModel.一个常见的错误是任何数据上下文都被称为 ViewModel。 This is done out of habit.这是出于习惯。 And you need to understand that such a name does not always correctly reflect the functionality of the Data Context.并且您需要了解这样的名称并不总是正确反映数据上下文的功能。 You also need to understand that the Data Context is a typical, but not mandatory, storage location for the ViewModel.您还需要了解数据上下文是 ViewModel 的典型但非强制性存储位置。 VM can be: in resources (this is quite often used); VM 可以是: 在资源中(这是经常使用的); in a static member (for example, Singlton is sometimes used);在 static 成员中(例如,有时使用 Singlton); received from some service, locator;从某些服务、定位器收到; and many other options.和许多其他选项。

I hope it is already clear that the VM is a reflection of the Model. And its connection with the View is "weak".我希望已经清楚 VM 是 Model 的反映。它与 View 的连接是“弱”的。 The view uses the ViewModel.该视图使用 ViewModel。 But the ViewModel doesn't "know" anything about the View.但是 ViewModel 并不“了解”有关 View 的任何信息。 In relation to navigation, this means that you first need to understand how your navigation changes or depends on the state of the Model. In most cases, the implementation of navigation - no way.关于导航,这意味着您首先需要了解您的导航如何更改或取决于 Model 的 state。在大多数情况下,导航的执行 - 没办法。

And judging by the code you showed, this is your case.从您展示的代码来看,这就是您的情况。 And in this case, all navigation is implemented at the presentation layer.在这种情况下,所有导航都在表示层实现。 That is, your MainViewModel class is not really a ViewModel, but a View layer class. And if so, then you may well instead of ViewModel instances (EventsViewModel, SettingsViewModel, AnotherViewModel) - create and use View instances (EventsView, SettingsView, AnotherView).也就是说,您的 MainViewModel class 并不是真正的 ViewModel,而是一个视图层 class。如果是这样,那么您可能会代替 ViewModel 实例(EventsViewModel、SettingsViewModel、AnotherViewModel)——创建并使用 View 实例(EventsView、SettingsView、AnotherView) . Instances will be created once and will exist for the duration of the application session.实例将被创建一次,并将在应用程序 session 的持续时间内存在。

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

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