簡體   English   中英

如何讓一個viewmodel更新另一個viewmodel上的屬性?

[英]How can I make one viewmodel update a property on another viewmodel?

我需要一個簡單的例子來說明如何使一個viewmodel更新另一個viewmodel上的屬性。

這是'情況。 我有一個視圖和viewmodel負責顯示一個專輯列表。 我有另一個視圖和viewmodel負責添加新專輯(幾個文本框和一個按鈕)現在添加新專輯如何告訴另一個視圖中的Collection已添加新專輯? 我讀到了可以為我做這個的框架,但我試圖學習所以我不會使用框架來存在...

以下是Josh Smith的經典演示應用程序提供的一些拼圖,展示了如何使用事件來支持mvvm提供的可測試性和松散情侶

數據

這不是cource的視圖模型,但大多數有趣的應用程序都有數據,它必須來自某個地方! 並且在添加新項目時持有事件是一個明顯且方便的候選者:

public class CustomerRepository
{
    ...

    /// <summary>Raised when a customer is placed into the repository.</summary>
    public event EventHandler<CustomerAddedEventArgs> CustomerAdded;

    /// <summary>
    /// Places the specified customer into the repository.
    /// If the customer is already in the repository, an
    /// exception is not thrown.
    /// </summary>
    public void AddCustomer(Customer customer)
    {
        if (customer == null) throw new ArgumentNullException("customer");
        if (_customers.Contains(customer)) return;

        _customers.Add(customer);

        if (CustomerAdded != null)
            CustomerAdded(this, new CustomerAddedEventArgs(customer));
    }

    ...
}

貝殼

考慮使用可能通過管理工作空間來協調給定演示文稿的視圖模型。 有些人可能稱之為經理(yuk!)或MainViewModel。 我喜歡ShellViewModel。 此視圖模型具有創建新項目的命令:

public class MainWindowViewModel : WorkspaceViewModel
{

    readonly CustomerRepository _customerRepository;

    public MainWindowViewModel(...)
    {
        _customerRepository = new CustomerRepository(customerDataFile);
    }

    void _createNewCustomer()
    {
        var newCustomer = Customer.CreateNewCustomer();
        var workspace = new CustomerViewModel(newCustomer, _customerRepository);
        Workspaces.Add(workspace);
        _setActiveWorkspace(workspace);
    }

    ObservableCollection<WorkspaceViewModel> _workspaces;

    void _setActiveWorkspace(WorkspaceViewModel workspace)
    {
        var collectionView = CollectionViewSource.GetDefaultView(Workspaces);
        if (collectionView != null)
            collectionView.MoveCurrentTo(workspace);
    }

 }

模型對象

您是否注意到靜態工廠構造函數方法(Customer.CreateNewCustomer)? 它清楚地表明了它的目的是什么,並提供了一個封裝創建新客戶所涉及的任何復雜性的機會。

模型對象ViewModel包裝器

這通常源於使INPC通知易於使用的基類,因為它是數據綁定的基礎。 請注意,Email屬性是直接傳遞給模型對象的email屬性,但DisplayNAme純粹是UI驅動的。 在添加新項目的情況下,它恰當地說...“新Cistomer”:

public class CustomerViewModel : WorkspaceViewModel, IDataErrorInfo
{

    public CustomerViewModel(Customer customer, CustomerRepository customerRepository)
    {
        if (customer == null) throw new ArgumentNullException("customer");
        if (customerRepository == null) throw new ArgumentNullException("customerRepository");

        _customer = customer;
        _customerRepository = customerRepository;
     }

    readonly Customer _customer;

    public string Email
    {
        get { return _customer.Email; }
        set
        {
            if (value == _customer.Email) return;

            _customer.Email = value;
            base.OnPropertyChanged("Email");
        }
    }

    public override string DisplayName
    {
        get {
            if (IsNewCustomer)
            {
                return Strings.CustomerViewModel_DisplayName;
            }
            ...

            return String.Format("{0}, {1}", _customer.LastName, _customer.FirstName);
        }
    }


    #region Save Command

    /// <summary>
    /// Returns a command that saves the customer.
    /// </summary>
    public ICommand SaveCommand
    {
        get
        {
            return _saveCommand ??
                   (_saveCommand = new RelayCommand(param => _save(), param => _canSave));
        }
    }
    RelayCommand _saveCommand;

    /// <summary>
    /// Returns true if the customer is valid and can be saved.
    /// </summary>
    bool _canSave
    {
        get { return String.IsNullOrEmpty(_validateCustomerType()) && _customer.IsValid; }
    }

    /// <summary>
    /// Saves the customer to the repository.  This method is invoked by the SaveCommand.
    /// </summary>
    void _save()
    {
        if (!_customer.IsValid)
            throw new InvalidOperationException(Strings.CustomerViewModel_Exception_CannotSave);

        if (IsNewCustomer)
            _customerRepository.AddCustomer(_customer);
        base.OnPropertyChanged("DisplayName");
    }

}

ViewModel的ViewModel集合

這可能支持過濾,排序,求和。 在添加新客戶的情況下,請注意它正在訂閱我們添加到存儲庫的事件。 另請注意,它使用了ObservableCollection,因為它內置了對數據綁定的支持。

public class AllCustomersViewModel : WorkspaceViewModel
{

    public AllCustomersViewModel(CustomerRepository customerRepository)
    {
        if (customerRepository == null) throw new ArgumentNullException("customerRepository");

        _customerRepository = customerRepository;

        // Subscribe for notifications of when a new customer is saved.
        _customerRepository.CustomerAdded += OnCustomerAddedToRepository;

        // Populate the AllCustomers collection with CustomerViewModels.
        _createAllCustomers();              
    }

    /// <summary>
    /// Returns a collection of all the CustomerViewModel objects.
    /// </summary>
    public ObservableCollection<CustomerViewModel> AllCustomers
    {
        get { return _allCustomers; }
    }
    private ObservableCollection<CustomerViewModel> _allCustomers;

    void _createAllCustomers()
    {
        var all = _customerRepository
            .GetCustomers()
            .Select(cust => new CustomerViewModel(cust, _customerRepository))
            .ToList();

        foreach (var cvm in all)
            cvm.PropertyChanged += OnCustomerViewModelPropertyChanged;

        _allCustomers = new ObservableCollection<CustomerViewModel>(all);
        _allCustomers.CollectionChanged += OnCollectionChanged;
    }

    void OnCustomerViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        const string IsSelected = "IsSelected";

        // Make sure that the property name we're referencing is valid.
        // This is a debugging technique, and does not execute in a Release build.
        (sender as CustomerViewModel).VerifyPropertyName(IsSelected);

        // When a customer is selected or unselected, we must let the
        // world know that the TotalSelectedSales property has changed,
        // so that it will be queried again for a new value.
        if (e.PropertyName == IsSelected)
            OnPropertyChanged("TotalSelectedSales");
    }

    readonly CustomerRepository _customerRepository;

    void OnCustomerAddedToRepository(object sender, CustomerAddedEventArgs e)
    {
        var viewModel = new CustomerViewModel(e.NewCustomer, _customerRepository);
        _allCustomers.Add(viewModel);
    }

}

查看完整文章並下載代碼!

HTH,
Berryl

有幾種方法:

1) AlbumsVM知道CreateAlbumVM (例如,首先打開第二個)。 在這種情況下,你可以簡單地添加到相冊AlbumsVM使用所提供的細節CreateAlbumVM
2) CreateAlbumVM知道AlbumsVM 然后它可以將專輯插入AlbumsVM本身。
3) AlbumsVM從某處接收專輯作為ObservableCollection 然后CreateAlbumVM可以將新專輯插入到原始的ObservableCollection ,該專輯將反映在AlbumsVM
4)這些viewModel之間有一些中介提供事件AlbumWasAdded

只需像這樣實現您的屬性。

private bool _checked;
    public bool Checked
    {
        get { return _checked; }
        set
        {
            if (value != _checked)
            {
                _checked = value;
                OnPropertyChanged("Checked");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public virtual void OnPropertyChanged(string propertyName)
    {
        var handler = PropertyCHanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

然后將您的其他視圖模型訂閱到propertyChangedEvent並執行您需要執行的操作。 確保您的ViewModel實現INotifyPropertyChanged

您給人的印象是您認為每個View的Viewmodel都應該是隔離的類。 他們不是。 Viewmodels以View可以綁定它的方式重新打包底層數據。 因此,創建一個ObservableCollection <Album >並讓兩個Viewmodels引用它。 完成!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM