是否可以使整个WPF应用程序可以使用非静态类的实例?

时间:2014-02-21 21:50:26

标签: c# wpf mvvm view viewmodel

我有一个WPF应用程序,它包含MainWindow以及可以通过Page访问的各种MainWindow对象。我目前在User的{​​{1}}中实例化ViewModel类,它定义了权限属性,这些属性绑定到相应MainWindow中的各种属性:

View

现在,我想在每个public NavigationViewModel() { _currentUser = new User(_currentServerConnection, Environment.UserName); 对象User中访问同一个Page实例。从设计的角度来看,最合适的方法是什么?我已经在StackOverflow上读了多个线程,并得出结论我应该创建这个类ViewModels(这里没有意义,这个类有一个static),或者实例化它每个state。我还有其他选择吗?哦,我也读过关于Singleton类的内容,这显然是建议反对的。我觉得我在这里错过了一些基本概念。

5 个答案:

答案 0 :(得分:2)

不建议使用Singleton。建议不要在错误的地方或错误的方式使用单身人士。

你的整个问题都被尖叫为“正确”和“适当”的例子,说明何时使用单身人士是好的。

如果您的设计图表和代码中的大量对象指向另一个对象的完全相同的实例,并且不再需要该对象的第二个实例,那么您已经找到了单个实例的正确用法。根据你的描述,你处于这种状况。

现在,您还可以使用静态。静态和单例之间的唯一区别是单例在第一次使用之前不会被实例化。由于您可能在加载后有登录,因此您可能要等到第一次登录尝试发生以实例化您的单例。这就是为什么你要在静态上使用单例。

public class GlobalSettings : IGlobalSettings
{
    public static GlobalSettings Instance
    {
        get { return _Instance ?? (_Instance = new GlobalSettings()); }
    } static GlobalSettings _Instance;

    public GlobalSettings() 
    {
    }

    // More methods/properties here
}

Singletons也可以在带锁的多线程应用程序中正常工作。请参阅此文章:http://msdn.microsoft.com/en-us/library/ff650316.aspx

单身人士也非常容易进行单元测试或在IOC中使用。任何说过的人都没有意识到你可以简单地使用一个接口来描述单例,然后所有使用单例的对象都可以拥有该接口的实例。我使用惰性属性注入,如下所示,除非IOC库已经存在。我不会仅为此包含IOC库的膨胀。

    public static IGlobalSettings Settings
    {
        get { return _Settings ?? (_Settings = GlobalSettings.Instance); }
    } static IGlobalSettings _Settings;

或者您也可以让您的IOC控制器/工厂每次都返回您的Singleton实例作为您的界面。

答案 1 :(得分:1)

在所有视图模型中拥有任何共享数据的最简单方法是在公共基类中声明这些属性。如果所有视图模型都扩展了这个基类,那么它们的属性将全部可用。

如果你想要更深入一点,你可以有一个实现Singleton模式的类,以确保只有一个实例。我有一些大型WPF应用程序,它们具有基本视图模型,可以访问许多...Manager类,为所有扩展视图模型提供各种服务。

其中一个是StateManager类,它实现了Singleton Pattern并基本上保存了整个应用程序中常见的所有属性。这是暴露它的基类的属性:

public StateManager StateManager
{
    get { return StateManager.Instance; }
}

这就是我在UI中使用它的方式:

<RadioButton IsChecked="{Binding StateManager.SomeValue}" Content="all" />

答案 2 :(得分:1)

另一种方法是使用管理对象的创建和生命周期的内容,例如inversion of control container

如果您决定探索这种方法,您需要做的就是:

  1. 在您的应用程序(组合根)中有单个入口点,告诉容器哪些对象以及如何可用(在WPF中,这将是App
  2. 设计您的类,以便他们可以利用依赖注入(即您的视图模型不会创建用户实例,而是期望它将通过提供构造函数注入
  3. 不再担心视图模型代码中的对象生命周期(它不应位于视图模型职责范围内)
  4. Autofac示例:

    // App.xaml.cs
    var builder = new ContainerBuilder();
    builder.RegisterType<User>()
        .WithParameter("userName", Environment.UserName)
        // tell container only one instance of this object should be ever created
        .SingleInstance();
    
    
    // ViewModel.cs
    public ViewModel(User user)
    {
        // we don't care at this point whether user is single instance or not;
        // it's container's responsibility to handle it for us
        this.user = user;
    }
    

    向用户注入当前服务器连接可能会有问题(因为它在组合根设置中不可用),但仅使用factory method pattern就足以克服此问题。

答案 3 :(得分:0)

这取决于User与各种视图模型之间的关系。

一种方法是,如果有一个逻辑User实例,并且所有视图模型都反映了此单个用户的状态。在这种情况下,我认为最合乎逻辑的路径是在所有视图模型之间传递一个User实例。

假设您的代码是单线程的,单例模型也可以很好地工作。但是我一般反对在可变对象上使用这种模式。今天你的应用程序是单线程的,明天可能没有。很容易忘记你从现在开始一周或一年做出这个关键假设,并最终将自己置于一个非常糟糕的地方

另一方面,如果每个视图模型都有不同的逻辑User实例,那么每次只创建一个新实例。

答案 4 :(得分:0)

使用静态类和静态字段是实现它的一种方法。

另一种方法是将用户类对象作为参数传递给页面视图模型的构造函数。