Двунаправленная модель представления, синхронизирующая с “живыми” наборами и свойствами

Лямбда-выражения и имена функций

Лямбда-выражение не является именем функции . имена функций в Common Lisp определены как символов или (setf symbol) . лямбда-выражение в основном является встроенным синтаксисом для описания анонимной функции.

Обратите внимание, что лямбда-выражения сами по себе не имеют смысла в Common Lisp. Они появляются только в лямбда-форме (см. Ниже) и внутри формы со специальным оператором function.

Списки в виде форм

Является ли LAMBDA особым исключением из жестко установленного правила, согласно которому первый элемент вычисляемого выражения должен быть именем некоторого операция, или есть какой-то более непротиворечивый набор правил, который я неправильно понимаю?

blockquote>

Спецификация Common Lisp определяет, что существует только четыре формы на основе списка . Форма является допустимым куском кода на Лиспе.

  • специальные формы (форма начинается со специального оператора)
  • макроформы (форма начинается с макрооператора)
  • функциональные формы (форма начинается с оператора функции )
  • лямбда-формы (форма начинается с лямбда-выражения)

См. Common Lisp HyperSpec: Conses as Forms .

Обратите внимание, что в Common Lisp нет механизма, расширяющего это. Есть только эти четыре типа форм на основе списка. Можно подумать о расширениях: массивы как функции, объекты CLOS как функции, различные типы функций, такие как fexprs, переменные ... Ни один из них не поддерживается синтаксисом Common Lisp для форм на основе списков, и нет переносимого механизма для их добавления. .

LAMBDA

LAMBDA преследует в Common Lisp две разные цели:

  • это глава лямбда-выражения .
  • в качестве макроса LAMBDA. Это расширяет (lambda ....) в (function (lambda ....))

Макрос LAMBDA был добавлен в Common Lisp после определения первого языка CLtL1 для удобства, чтобы можно было писать (lambda (x) x) вместо (function (lambda (x) x)) или #'(lambda (x) x). Таким образом, это аббревиатура для формы специального оператора функции и делает код более простым и похожим на Схематически .

7
задан Community 23 May 2017 в 12:00
поделиться

6 ответов

Я тоже борюсь с двунаправленной синхронизацией двух коллекций для использования с WPF через MVVM. Я написал MVVM: оборачивать или не оборачивать? Насколько ViewModel должна оборачивать модель? (Часть 1) и MVVM: переносить или не переносить? Должны ли ViewModels также обертывать коллекции? (Часть 2) по вопросу, включая пример кода, который показывает двустороннюю синхронизацию. Однако, как отмечается в сообщениях, реализация не идеальна. Я бы квалифицировал это как доказательство концепции.

Мне нравятся фреймворки BLINQ , CLINQ и Obtics , о которых писал Alex_P. Это очень хороший способ получить одну сторону поведения при синхронизации. Может быть, другая сторона (от ВМ к Модели) может быть реализована альтернативным путем? Я только что разместил в своем блоге часть 3 , в которой обсуждаются некоторые из этих вопросов.

Насколько я могу судить, двунаправленная передача через BLINQ и CLINQ не поддерживается в тех случаях, когда оператор LINQ проецирует данные в новую структуру.

Однако похоже, что CLINQ может поддерживать двунаправленную синхронизацию в случаях, когда запрос LINQ возвращает тот же тип данных, что и базовая коллекция. Это скорее сценарий фильтрации, который не соответствует варианту использования ViewModel, заключающего данные в модель.

3
ответ дан 6 December 2019 в 21:13
поделиться

С моим библиотека ObservableComputations можно создать ObservableCollection, который является результатом вычислений по другому ObservableCollection и является synchoronized с нею. Вы делаете стандартные операции (добавьте, удалите) на исходном наборе: вычисленный Набор отражает все изменения:

Filtering<Order> expensiveOrders = orders.Filtering(o => o.Price > 25); 

expensiveOrders.CollectionChanged += (sender, eventArgs) =>
{
     // see the changes (add, remove, replace, move, reset) here
};

// Start the changing...
orders.Add(new Order(8, 30));
orders.RemoveAt(1);
orders[0].Price = 60;
orders[4].Price = 10;
orders.Move(5, 1);
orders[1] = new Order(10, 17);
0
ответ дан 6 December 2019 в 21:13
поделиться

Лично я использую Наблюдаемую Коллекцию в своей модели и своей видовой модели.

class Model
{
    public ObservableCollection<Foo> Foos;
}

class ViewModel
{
    public Model Model;
    public ObservableCollection<FooView> Foos;

    public ViewModel()
    {
        Model.Foos.CollectionChanged += OnModelFoosCollection_CollectionChanged;
    }

    void OnModelFoosCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
       Foo re;

       switch (e.Action)
       {
          case NotifyCollectionChangedAction.Add:
             re = e.NewItems[0] as Foo;
             if (re != null)
                AddFoo(re);  //For other logic that may need to be applied
             break;
          case NotifyCollectionChangedAction.Remove:
             re = e.OldItems[0] as Foo;
             if (re != null)
                RemoveFoo(re); 
             break;
          case NotifyCollectionChangedAction.Reset:
             Foos.Clear();
             /* I have an AddRange in an ObservableCollection-derived class
                You could do Model.Foo.ForEach(ree => AddFoo(ree));
             */
             var converter = 
                from ree in Model.Foo
                select new FooView(ree);
             Reports.AddRange(converter); 
             break;
          default:
             //exercise for the reader :)
             s_ILog.Error("OnModelFoosCollection_CollectionChangedDid not deal with " + e.Action.ToString()); 
             break;
       }
    }   

    void AddFoo(Foo f)
    {
        Foos.Add(new FooView(f));
    }

    void RemoveFoo(Foo f)
    {
       var match = from f in Foos
          where f.Model == f  //if you have a unique id, that might be a faster comparison
          select f;
       if(match.Any())
          Foos.Remove(match.First());
    }
}

Теперь, когда вы удаляете что-то из коллекции Foo модели, она автоматически удалит соответствующий FooView. Это соответствует тому, как я думаю о таких вещах. Если я хочу что-то удалить, то Модель - это то место, где действительно нужно что-то удалить.

Похоже на много кода, но на самом деле не так уж и много. Я уверен, что можно было бы построить общую версию, но IMO вы всегда заканчиваете тем, что вам нужна индивидуальная логика, связанная с добавлением/удалением элементов.

4
ответ дан 6 December 2019 в 21:13
поделиться

Единственная ситуация, когда вам может потребоваться двусторонняя синхронизация, - это когда элемент управления, который вы используете для визуализации своей коллекции виртуальных машин, не сообщает вам о намерении пользователя создать или удалить элемент. Т.е. элемент управления имеет дело непосредственно с вашей коллекцией виртуальных машин, и ЕДИНСТВЕННЫЙ способ узнать, что элемент был добавлен / удален, - это мониторинг коллекции виртуальных машин. Если это не так, вы можете реализовать одностороннюю синхронизацию и добавлять / удалять элементы непосредственно в коллекции модели.

РЕДАКТИРОВАТЬ: Возьмем, к примеру, элемент управления WPF DataGrid , привязанный к наблюдаемой коллекции ItemViewModels. Если для его свойства CanUserAddRows установлено значение true и пользователь начинает вводить текст в пустой строке внизу, DataGrid будет использовать конструктор по умолчанию вашего { {1}} ItemViewModel, чтобы создать свободный элемент , а затем добавит его в коллекцию .Нет никаких указаний от DG, что он хочет добавить элемент в коллекцию.c Я не могу придумать другого сложного элемента управления { {1}} достаточно, чтобы иметь возможность добавлять элементы в коллекцию самостоятельно.
Противоположный сценарий - это когда у вас есть ListView , привязанный к вашей коллекции, и команда , которая указывает на намерение пользователя добавить новый item - затем в обработчике команд вы просто добавляете новый элемент в DataModel и позволяете односторонней синхронизации делать остальную работу. В этом случае ListView не может добавлять в коллекцию, которую представляет.

Что касается самого процесса синхронизации, посмотрите проект Bindable LINQ - он может минимизировать объем кода и улучшить читаемость. Например, код, опубликованный Томом, будет выглядеть примерно так:

class ViewModel
{
  public Model Model;
  public ObservableCollection<FooView> Foos;
  public ViewModel()
  {
    Foos = from foo in Model.Foos.AsBindable()
           select new FooView(foo);
  }
}

РЕДАКТИРОВАТЬ 2: После использования B-LINQ в течение некоторого времени я должен сказать, что у вас могут возникнуть проблемы с производительностью. Я использовал его для синхронизации коллекций относительно больших коллекций (сотни элементов) с десятками элементов, добавляемых и удаляемых каждую секунду, и мне пришлось отказаться от него и реализовать синхронизацию так, как предлагал Том.
Я все еще использую B-LINQ, хотя в тех частях проекта, где коллекции небольшие и производительность не является проблемой.

3
ответ дан 6 December 2019 в 21:13
поделиться

Я написал несколько вспомогательных классов для обертывания наблюдаемых коллекций бизнес-объектов в их аналогах модели представления здесь , возможно, его следует расширить, чтобы пойти другим путем. всегда ищу помощь ...

1
ответ дан 6 December 2019 в 21:13
поделиться

Я предложил общий фреймворк Undo / Redo, основанный на MVVM, который использует некоторые техники, связанные с описанной вами проблемой. Он использует коллекции, реализующие этот интерфейс:

public interface MirrorCollectionConversor<V, D>
{
   V GetViewItem(D modelItem, int index);
   D GetModelItem(V viewItem, int index);
}

(V - для элементов ViewModel, D - для элементов модели)

Используя этот интерфейс, он автоматически синхронизирует коллекцию viewmodel при изменении коллекции модели. Если вы изменяете модель представления, изменения просто перенаправляются в коллекцию модели.

Функция GetViewItem дает вам некоторую гибкость в том, как объекты viewmodel связаны с его аналогами модели.

Подробности вы можете найти здесь

(признаю, что конструкция довольно сложная, и я буду очень рад выслушать предложения).

1
ответ дан 6 December 2019 в 21:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: