MVVM - DataContext & numerous ViewModels

本文关键字:numerous ViewModels amp DataContext MVVM | 更新日期: 2024-11-06 23:36:48

我一直在尝试将MVVM设计模式应用于我的最新项目。 我看了无数的视频,阅读了大量的教程,同时也浏览了人们的演示代码。

我有一个作业对象和一个任务对象。 我已经为每个创建了ViewModel。 我还创建了一个 AllJobs 和 AllTasks ViewModel,分别创建了JobViewModelsTaskViewModelsObservableCollection

如果我将 MainWindow 的 DataContext 设置为 AllJobsViewModel 的实例,那么我可以访问名为"AllJobs"的ObservableCollection并根据需要使用它。 但是,鉴于这是 DataContext,我如何在同一窗口中访问我的 AllTasksViewModel AllTasks 集合?

MVVM - DataContext & numerous ViewModels

如果您将 ViewModel 设计为镜像业务对象,那么您的方向就错了。相反,视图模型应该特定于视图。ViewModel 和它的 View 之间应该有一个严格的 1:1 关系 - 换句话说:它们形成一对

模型部分独立于此区别,这完全取决于业务案例和要面向的平台。

您的要求(用例)控制应用程序的视图部分。业务域控制模型的设计。然后,ViewModel 在两者之间进行调解。它仅满足应用程序视图部分的技术要求。

当涉及到模型和视图模型时,很少有 1:1 的关系。您可以使用将多个模型甚至多个视图模型组合为一个视图模型的视图模型。我相信这也是您情况的首选解决方案。

MVVM 背后的要点是尽可能多地分离层,尤其是 UI 和模型。请参阅我的最新答案,看看我的意思是什么 模型/视图模型是什么?

无需为每个项目创建单独的视图模型。您需要创建一个包含所需所有信息的单一视图模型,并将该视图模型作为主窗口的 DataContext。

否则,创建另一个视图模型,其中包含您的AllJobsViewModel和AllTasksViewModel。并将新的视图模型作为主窗口的数据上下文。

您可以使用 EventAggregator 或 MessageBus。

这个想法是让你的视图模型订阅他们想要响应的事件。

我将发布订阅模式用于复杂的类依赖项:

视图模型:

    public class ViewModel : ViewModelBase
    {
        public ViewModel()
        {
            CloseComand = new DelegateCommand((obj) =>
                {
                    MessageBus.Instance.Publish(Messages.REQUEST_DEPLOYMENT_SETTINGS_CLOSED, null);
                });
        }
}

窗:

public partial class SomeWindow : Window
{
    Subscription _subscription = new Subscription();
    public SomeWindow()
    {
        InitializeComponent();
        _subscription.Subscribe(Messages.REQUEST_DEPLOYMENT_SETTINGS_CLOSED, obj =>
            {
                this.Close();
            });
    }
}

你可以利用Bizmonger.Patterns来获取MessageBus。

消息总线

public class MessageBus
{
    #region Singleton
    static MessageBus _messageBus = null;
    private MessageBus() { }
    public static MessageBus Instance
    {
        get
        {
            if (_messageBus == null)
            {
                _messageBus = new MessageBus();
            }
            return _messageBus;
        }
    }
    #endregion
    #region Members
    List<Observer> _observers = new List<Observer>();
    List<Observer> _oneTimeObservers = new List<Observer>();
    List<Observer> _waitingSubscribers = new List<Observer>();
    List<Observer> _waitingUnsubscribers = new List<Observer>();
    int _publishingCount = 0;
    #endregion
    public void Subscribe(string message, Action<object> response)
    {
        Subscribe(message, response, _observers);
    }
    public void SubscribeFirstPublication(string message, Action<object> response)
    {
        Subscribe(message, response, _oneTimeObservers);
    }
    public int Unsubscribe(string message, Action<object> response)
    {
        var observers = new List<Observer>(_observers.Where(o => o.Respond == response).ToList());
        observers.AddRange(_waitingSubscribers.Where(o => o.Respond == response));
        observers.AddRange(_oneTimeObservers.Where(o => o.Respond == response));
        if (_publishingCount == 0)
        {
            observers.ForEach(o => _observers.Remove(o));
        }
        else
        {
            _waitingUnsubscribers.AddRange(observers);
        }
        return observers.Count;
    }
    public int Unsubscribe(string subscription)
    {
        var observers = new List<Observer>(_observers.Where(o => o.Subscription == subscription).ToList());
        observers.AddRange(_waitingSubscribers.Where(o => o.Subscription == subscription));
        observers.AddRange(_oneTimeObservers.Where(o => o.Subscription == subscription));
        if (_publishingCount == 0)
        {
            observers.ForEach(o => _observers.Remove(o));
        }
        else
        {
            _waitingUnsubscribers.AddRange(observers);
        }
        return observers.Count;
    }
    public void Publish(string message, object payload)
    {
        _publishingCount++;
        Publish(_observers, message, payload);
        Publish(_oneTimeObservers, message, payload);
        Publish(_waitingSubscribers, message, payload);
        _oneTimeObservers.RemoveAll(o => o.Subscription == message);
        _waitingUnsubscribers.Clear();
        _publishingCount--;
    }
    private void Publish(List<Observer> observers, string message, object payload)
    {
        Debug.Assert(_publishingCount >= 0);
        var subscribers = observers.Where(o => o.Subscription.ToLower() == message.ToLower());
        foreach (var subscriber in subscribers)
        {
            subscriber.Respond(payload);
        }
    }
    public IEnumerable<Observer> GetObservers(string subscription)
    {
        var observers = new List<Observer>(_observers.Where(o => o.Subscription == subscription));
        return observers;
    }
    public void Clear()
    {
        _observers.Clear();
        _oneTimeObservers.Clear();
    }
    #region Helpers
    private void Subscribe(string message, Action<object> response, List<Observer> observers)
    {
        Debug.Assert(_publishingCount >= 0);
        var observer = new Observer() { Subscription = message, Respond = response };
        if (_publishingCount == 0)
        {
            observers.Add(observer);
        }
        else
        {
            _waitingSubscribers.Add(observer);
        }
    }
    #endregion
}

}

订阅

public class Subscription
{
    #region Members
    List<Observer> _observerList = new List<Observer>();
    #endregion
    public void Unsubscribe(string subscription)
    {
        var observers = _observerList.Where(o => o.Subscription == subscription);
        foreach (var observer in observers)
        {
            MessageBus.Instance.Unsubscribe(observer.Subscription, observer.Respond);
        }
        _observerList.Where(o => o.Subscription == subscription).ToList().ForEach(o => _observerList.Remove(o));
    }
    public void Subscribe(string subscription, Action<object> response)
    {
        MessageBus.Instance.Subscribe(subscription, response);
        _observerList.Add(new Observer() { Subscription = subscription, Respond = response });
    }
    public void SubscribeFirstPublication(string subscription, Action<object> response)
    {
        MessageBus.Instance.SubscribeFirstPublication(subscription, response);
    }
}