首页 > 解决方案 > 最初在 C# 中的 XAML 中实例化 ViewModel 时如何重新实例化它

问题描述

我正在开发一个应用程序并尝试尽可能多地遵循 MVVM,因此有许多具有相应 ViewModes 的视图。我正在反序列化使用 XAML 在视图中实例化的 ViewModel。例如,如果 View 称为“ExampleView”,而 ViewModel 称为“ExampleViewModel”。ViewModel 通过这样做在 ExampleView 中实例化......

<UserControl.Resources>
        <local:ExampleViewModel x:Key="ViewModel" />
</UserControl.Resources>

使用后面的代码从视图中获取/设置 ViewModel(通常这只是一个获取,但我尝试在反序列化后设置 ViewModel)。

    public ExampleViewModel ViewModel
        {
            get { return (ExampleViewModel)this.Resources["ViewModel"];  }
            set
            {
                if (this.Resources["ViewModel"]!=value)
                {
                    this.Resources["ViewModel"] = value;
                }
            }
        }

这不起作用,但我认为原因是 PropertyChanged 没有被解雇。因此,在 ExampleViewModel 中,我输入了一种方法来刷新每个属性。例如 ...

public void RefreshAllProperties()
        {
            NotifyPropertyChanged("Property1");
            NotifyPropertyChanged("Property2");
            ...
        }

其中 NotifyPropertyChanged 是...

   private void NotifyPropertyChanged([CallerMemberName] string PropertyName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
        }

虽然这没有通过代码气味测试,但我试图在寻找更优雅的东西的过程中理解。然而,我惊讶地发现它不起作用。

我更愿意在 XAML 中实例化 ViewModel。反序列化后是否有重新实例化 ViewModel 的最佳实践?

修改后的问题

关于将 ViewModel 创建移动到 View 类的构造函数中的任何评论?这是更好的设计模式吗?

ExampleViewModel exampleViewModel;

        public ExampleView()
        {
            InitializeComponent();
            ExampleViewModel = new ExampleViewModel();
            this.DataContext = ExampleViewModel;
        }

        public ExampleViewModel ViewModel
        {
            get { return exampleViewModel;  }
            set
            {
                if (exampleViewModel!=value)
                {
                    exampleViewModel = value;
                    NotifyPropertyChanged();
                    
                }
            }
        }

标签: c#wpfxaml

解决方案


我以前没有见过在 ResourceDictionary 中定义的 ViewModel。我倾向于在代码隐藏中初始化我的 ViewModel(我知道你提到你想将它保留在 XAML 中),因为我可以更直接地控制页面 DataContext 以及它最终更新的时间(比如在你的情况下反序列化之后)。在运行时修改 ResourceDictionary 似乎是一种危险的方法,并且WPF 中的 ResourceDictionary 没有实现 INotifyPropertyChanged或任何其他更改接口INotifyCollectionChanged,这意味着它不会通知任何其键值对已以某种方式更改的任何内容。

总而言之:我的答案是不要在 ResourceDictionary 中定义您的 VM,而是在您的页面代码隐藏中管理它,您可以确保在 VM 或其状态更改时适当更新 DataContext。


推荐阅读