MvvmLight в классе, который использует композицию - PullRequest
2 голосов
/ 17 марта 2020

У меня есть ViewModel, производная от MvvmLight.ViewModelBase, которая использует композицию для повторного использования других классов:

Упрощенная версия классов, которые я хочу использовать в композиции:

class TimeFrameFactory
{
    public DateTime SelectedTime {get; set;}

    public ITimeFrame CreateTimeFrame() {...}
}

class GraphFactory
{
     public int GraphWidth {get; set;}

     public IGraph CreateGraph(ITimeframe timeframe) {...}
}

Моя ViewModel, производная от MvvmLight ViewModelBase, представляет собой композицию из этих двух:

class MyViewModel : ViewModelBase
{
    private readonly TimeFrameFactory timeFrameFactory = new TimeFrameFactory();
    private readonly GraphFactory graphFactory = new GraphFactory();

    private Graph graph;

    // standard MVVM light method to get/set a field:
    public Graph Graph
    {
        get => this.Graph;
        private set => base.Set(nameof(Graph), ref graph, value);
    }

    // this one doesn't compile:
    public DateTime SelectedTime 
    {
        get => this.timeFrameFactory.SelectedTime;
        set => base.Set(nameof(SelectedTime), ref timeFrameFactory.SelectedTime, value);
    }

    // this one doesn't compile:
    public int GraphWidth
    {
        get => this.timeFrameFactory.GraphWidth;
        set => base.Set(nameof(GraphWidth), ref timeFrameFactory.GraphWidth, value);
    }

    public void CreateGraph()
    {
        ITimeFrame timeFrame = this.timeFrameFactory.CreateTimeFrame();
        this.Graph = this.GraphFactory.CreateGraph(timeFrame);
    }
}

Get / Set с полем работает, но если я хочу перенаправить установку свойства в составной объект, я не могу использовать base.Set

set => base.Set(nameof(GraphWidth), ref timeFrameFactory.GraphWidth, value);

ссылка не разрешена для свойств.

Конечно, я мог бы написать:

    public int GraphWidth
    {
        get => this.timeFrameFactory.GraphWidth;
        set
        {
            base.RaisePropertyChanging(nameof(GraphWidh));
            base.Set(nameof(GraphWidth), ref timeFrameFactory.GraphWidth, value);
            base.RaisePropertyChanged(nameof(GraphWidh));
        }
    }

Довольно неприятно, если вы должны сделать это для много свойств. Есть ли хороший способ сделать это, возможно, похожий на ObservableObject.Set?

1 Ответ

1 голос
/ 17 марта 2020

Ну, базовый метод должен уметь как читать (для сравнения), так и записывать переданное поле / свойство, поэтому ссылка.

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

A) Принимает делегатов-получателей / установщиков. (Подробно / раздражает)

public int GraphWidth
{
    get => this.timeFrameFactory.GraphWidth;
    set => base.Set(nameof(GraphWidth), () => timeFrameFactory.GraphWidth, x => timeFrameFactory.GraphWith = x, value);
}

или

B) Пропускает Expression<Func<T>>, содержащее свойство, и использует отражение, чтобы извлечь свойство и получить / установить его в базе (медленно, но потенциально может извлечь имя тоже)

public int GraphWidth
{
    get => this.timeFrameFactory.GraphWidth;
    set => base.Set(() => timeFrameFactory.GraphWidth, value);
}
...