Singleton ViewModel WPF - PullRequest
       14

Singleton ViewModel WPF

0 голосов
/ 06 мая 2020

Я создал сетку данных, используя шаблон MVVM ( почти в точности этот пример ). Конечная цель состоит в том, чтобы иметь график, который отображает все данные из этой сетки данных, И эта сетка данных должна обновляться, когда точка графика перемещается вручную (перетаскивание). Построенные данные представляют собой набор входных данных для робота.

Я намеревался построить его с помощью 1 модели (список входных параметров), 2 моделей просмотра (одна для таблицы данных и одна для графика) и 2 представления (одно и то же окно).

Проблема: обе модели просмотра должны использовать / обновлять один и тот же ObservableCollection, содержащий список входов.

Чтобы решить эту проблему, я попробовал несколько подходов:

  • Шаблон посредника - я его не понимаю
  • Внедрение зависимостей - То же, что и для шаблона посредника, все примеры Мне было сложно понять
  • Singleton patter - кажется, я понимаю это, но не могу его правильно реализовать (я использую этот пример , который я считаю понятным)

Чтобы упростить задачу, в настоящее время я сосредоточен только на сетке данных. Итак, используя шаблон Singleton + MVVM, я пытаюсь заставить его работать так же, как и раньше (команды для добавления / удаления строки, перетаскивания, обновления ObservableCollection ).

Итак, это одноэлементный класс:

class SingletonDoliInputCollection : ViewModelBase
{
    #region Events
    void OnDoliCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        // Update item count
        this.ItemCount = this.DoliInputCollection.Count;

        // Resequence list
        SetCollectionSequence(this.DoliInputCollection);
    }
    #endregion

    #region Fields
    private ObservableCollection<DoliInput> _doliInputCollection;
    private int _itemCount;
    //Singleton
    private static SingletonDoliInputCollection _instance;
    #endregion

    #region Singleton Constructor
    private SingletonDoliInputCollection() { }
    #endregion

    #region Properties   
    public ObservableCollection<DoliInput> DoliInputCollection
    {
        get => _doliInputCollection;
        set
        {
            _doliInputCollection = value;
            OnPropertyChanged("DoliInputCollection");
        }
    }

    public static SingletonDoliInputCollection GetInstance(ObservableCollection<DoliInput> DoliInputCollection)
    {
        if (_instance == null)
        {
            _instance = new SingletonDoliInputCollection();
            _instance.Initialise(DoliInputCollection);
        }

        return _instance;
    }


    public int ItemCount
    {
        get => _itemCount;
        set
        {
            _itemCount = value;
            OnPropertyChanged("ItemCount");
        }
    }
    /// <summary>
    /// Return selected item in the grid
    /// </summary>
    public DoliInput SelectedItem { get; set; }
    #endregion

    #region Manage Sequencing
    /// <summary>
    /// Resets the sequential order of a collection.
    /// </summary>
    /// <param name="targetCollection">The collection to be re-indexed.</param>
    public static ObservableCollection<T> SetCollectionSequence<T>(ObservableCollection<T> targetCollection) where T : ISequencedObject
    {
        // Initialize
        var sequenceNumber = 1;

        // Resequence
        foreach (ISequencedObject sequencedObject in targetCollection)
        {
            sequencedObject.SequenceNumber = sequenceNumber;
            sequenceNumber++;
        }

        // Set return value
        return targetCollection;
    }
    #endregion

    #region Private Methods
    #region Initialise
    private void Initialise(ObservableCollection<DoliInput> DoliInputCollection)
    {
        //Create inputList
        _instance.DoliInputCollection = new ObservableCollection<DoliInput>();

        //Add items
        _instance.AddInput("Load", 3, 2, 1);
        _instance.AddInput("Position", 3, 11, 1);
        _instance.AddInput("Position", 3, 2, 4);
        _instance.AddInput("Load", 3, 2, 1);

        //Subscribe to the event that gets trigger when change occurs
        _instance.DoliInputCollection.CollectionChanged += OnDoliCollectionChanged;

        //Start indexing items
        this.DoliInputCollection = SetCollectionSequence(this.DoliInputCollection);

        //Update if changes
        this.OnPropertyChanged("DoliInputCollection");
        this.OnPropertyChanged("GridParam");
    }
    #endregion

    #endregion

    #region Public Methods
    public void AddInput(string CTRL, double Destination, double Speed, double Duration)
    {
        this.DoliInputCollection.Add(new DoliInput(CTRL, Destination, Speed, Duration));
    }
    #endregion

}

Класс ViewModel выглядит так:

public class DataGridVM : ViewModelBase
{
    #region Constructor

    public ObservableCollection<DoliInput> DoliInputCollection { get; set; }
    public DoliInput SelectedItem { get; set; }

    public DataGridVM()
    {
        //ObservableCollection<DoliInput> DoliInputCollection = new ObservableCollection<DoliInput>();
        SingletonDoliInputCollection doliInputs = GetDoliInputCollectionInstance(DoliInputCollection);
        DoliInputCollection = doliInputs.DoliInputCollection;
        SelectedItem = doliInputs.SelectedItem;
        Console.WriteLine(doliInputs.DoliInputCollection.ToString());
    }

    #endregion

    #region Properties
    public ICommand DeleteItem { get; set; }
    public ICommand AddRow { get; set; }

    #endregion

    #region Private Methods
    #region Initialise
    private static SingletonDoliInputCollection GetDoliInputCollectionInstance(ObservableCollection<DoliInput> DoliInputs)
    {
        SingletonDoliInputCollection singleton = SingletonDoliInputCollection.GetInstance(DoliInputs);
        return singleton;
    }
    #endregion

    #endregion

}

А для представления вот только пример форматирования столбца:

<!--[...]-->
xmlns:dataGrid="clr-namespace:InteractiveGraph.Grid"
<!--[...]-->
<DataGridTextColumn Binding="{Binding Path=(dataGrid:DoliInput.Speed), Mode=TwoWay}" Header="Speed" />
<!--[...]-->

Последняя упрощенная версия модели (есть еще 3 свойства: CTRL, назначение и продолжительность, здесь не отображаются)

public class DoliInput : ObservableObject, ISequencedObject
{
    #region Fields
    private double _speed;
    private int _seqNb;
    #endregion

    #region Properties

    public double Speed 
    { 
        get => _speed; 
        set 
        { 
            _speed = value; 
            OnPropertyChanged("Speed"); 
        } 
    }

    public int SequenceNumber 
    { 
        get => _seqNb;
        set
        {
            _seqNb = value;
            OnPropertyChanged("SequenceNumber");
        }
    }

    #endregion

    #region Constructor

    public DoliInput(){  }

    public DoliInput(string CTRL, double destination, double speed, double duration)
    {
        this._speed = speed;
    }
    #endregion
}

Я постарался сделать это как можно короче. Если нужна дополнительная информация, я могу ее добавить.

Disclamer : Очевидно, я не профессиональный программист. Я занимаюсь этим на стороне и стараюсь узнавать новое. Если вы думаете, что весь мой подход к этому коду неверен, я полностью открыт для нового.

1 Ответ

0 голосов
/ 06 мая 2020

Внедрение зависимостей означает, что вы передаете зависимости (в данном случае точки данных) объекту (в данном случае модель представления) вместо того, чтобы объекты создавали свои собственные зависимости и имели проблемы, подобные той, что у вас есть прямо сейчас, когда зависимости, которые должны быть разделены.

Вы можете централизовать данные в каком-то объекте, который передается конструкторам обеих моделей представления. Однако это потребует от вас создания событий / реализации INotifyPropertyChanged, чтобы обе модели представления знали об изменении и вызывали событие PropertyChanged.

Вы также можете иметь одну модель представления, связанную двумя разными просмотров, но убедитесь, что вы не нарушаете принцип единой ответственности. Я думаю, что этот подход следует предпочесть. Обратите внимание, что вы не ограничены отношениями 1-1 между моделями представления и представлениями. У вас может быть много представлений, привязанных к одной модели представления, привязка представления к нескольким моделям представления и т. Д. c ...

В любом случае избегайте одиночных представлений, по крайней мере, для этого случая.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...