【问题标题】:Best Way to Pass Data to new ViewModel when it is initiated启动时将数据传递给新 ViewModel 的最佳方式
【发布时间】:2013-08-28 20:54:27
【问题描述】:

我正在使用 MVVM-Light 框架开发 WPF 数据库应用程序。我正在使用 SimpleIOC 注入我的数据服务,并且我的 ViewModel 连接到 XAML 文件中的视图。但是,当打开新的视图模型时,我通常还需要将另一个对象传递给视图模型(假设我传递了一个 CarId 的整数,以便我可以从数据库中获取实际的 Car)。

现在我在 InitializeComponent() 之后通过在视图上使用信使来传递它。然后由 View Model 捕获。这目前确实有效,但它有一些挫折。

首先,直到调用视图模型的构造函数之后才会发送消息。假设我在 ViewModel 中有一个 ThisCar 对象属性,并且我有第二个属性,比如一个名为 Brand 的字符串,它返回 ThisCar.Brand。

    public const string ThisPersonPropertyName = "ThisCar";
    private Model.Car _thisCar;
    public Model.Car ThisCar
    {
        get
        {
            return _thisCar;
        }

        set
        {
            if (_thisCar== value)
            {
                return;
            }

            RaisePropertyChanging(ThisCarPropertyName);
            _thisCar= value;
            RaisePropertyChanged(ThisCarPropertyName);
        }
    }

    public const string BrandPropertyName = "Brand";
    public string Brand
    {
        get
        {
            return ThisCar.Brand;
        }

        set
        {
            if (ThisCar.Brand == value)
            {
                return;
            }

            RaisePropertyChanging(BrandPropertyName);
            ThisCar.Brand = value;
            RaisePropertyChanged(BrandPropertyName);
        }
    }

现在,当构造函数被调用时,我必须像这样在 View Model 构造函数中初始化 ThisCar,否则在创建 ViewModel 时我会在 ThisCar.Brand 上收到 null 错误。

ThisCar = new CarObject();

然后,初始化为空对象后,会调用Message,我会根据Car ID从Database中拉取真正的Car。

ThisCar = webService.GetCar(carId);

但是,当我这样做时,品牌属性不会更新,因为没有任何东西为品牌调用 OnPropertyChanged。

我有两个变通方法,但它们对我来说更像是黑客。首先是为需要更新的任何属性手动调用 OnPropertyChanged。其次是我删除了所有的小属性,并将所有内容直接绑定到 ThisCar 属性(这意味着我必须在我的模型中实现 INotifyPropertyChanged)。

如果我只是挑剔,或者是否有更好的方法来做到这一点,请告诉我。我这样做的方式很有效,但就是不适合我。谢谢。

【问题讨论】:

    标签: c# wpf mvvm mvvm-light


    【解决方案1】:

    好的,这就是我想出的,如果这是一个可怕的想法,请告诉我。

    我创建了一个名为 IRepository 的接口,因为我使用依赖注入来创建视图模型。这是实现:

    public interface IRepository
    {
        void GetCarId(Action<int> callback);
        void SetCarId(int value);
    }
    

    接下来我创建一个继承自 IRepository 的类

    public class Repository : IRepository
    {
        private int CarId;
        public void GetCarId(Action<int> callback)
        {
            callback(CarId);
        }
    
        public void setDictionary(int carId)
        {
            CarId = carId;
        }
    }
    

    现在要将值传递到存储库中,我将其放入父视图模型中

     r.SetCarId(13);
    

    为了在新的视图模型中接收,我将它放在视图模型构造函数中:

        public View2ViewModel(IChildView i, IRepository r)
        {
            int CarId;
            r.GetCarId((id) => CarId = id);
            thisCar = GetCarFromDatabase(CarId);
        }
    

    在我看来,这可以解决问题,而不会破坏 MVVM 模式,而且由于我使用的 IOC 容器将所有接口成员创建为静态的,因此我将在我的其余视图中拥有这些数据。

    我遇到的主要问题是它感觉像是一个全局变量,但这是我能想到的最好的。请让我知道这是否是一个非常糟糕的主意。谢谢。

    【讨论】:

    • 当您有一个目录应用程序并且您的视图被回收时,这将不起作用。由于您只记得显示的最后一个项目,因此您丢失了活动的项目堆栈。
    【解决方案2】:

    我将投票支持使模型能够通知那里的更改,即在模型中实现 INotifyPropertyChanged。两个原因:

    1. 您可能需要在多个位置/视图使用同一个模型,并且您不希望在每个 ViewModel 中都注意哪些属性更改会引发哪些其他属性更改。坦率地说,那是混乱和错误的。

    2. 有时,在 VM 层,我们可能需要监听模型的变化,因此在这种情况下,自我通知模型也会有所帮助。

    谢谢

    【讨论】:

    • 现在说得通了,我只记得我第一次学习 MVVM 时,看到的信息是让 INotifyPropertyChange 脱离模型。您对不使用 messenger 将参数传递给视图模型有什么建议吗?
    猜你喜欢
    • 2014-02-12
    • 2016-12-03
    • 2014-01-27
    • 2014-07-18
    • 2010-12-08
    • 1970-01-01
    • 2015-01-20
    • 2016-06-14
    • 1970-01-01
    相关资源
    最近更新 更多