Динамическое связывание с пользовательским бизнес-объектом во время выполнения - PullRequest
6 голосов
/ 15 февраля 2012

Я работаю над проектом Web Forms , который загружает результаты запросов Sql в DataTable s.

Эти DataTable sдошел до внешнего интерфейса, где мы связали их с веб-элементом управления Repeater .

Это прекрасно работает.Однако теперь мы хотели бы связать наши собственные классы вместо DataTable.К сожалению, то, что я считал очевидным ответом, не сработало (реализация IDictionary<string, object> в нашем классе).

Что нам нужно, чтобы Eval связывался с Datum без создания конкретного свойства для каждой привязки?Понятно, что DataRow не должен конкретно реализовывать каждое свойство, которое мы связываем.Итак, почему-то кажется, что Eval может искать значения свойств по имени в DataRow.

Вот пользовательский класс

public class Datum: IDictionary<string, object>
{
    private Dictionary<string, object> _entries;

    public Datum()
    {
        _entries = new Dictionary<string, object>();
    }

    public object this[string s]
    {
        get
        {
            return this._entries[s];
        }
    }

    ...
}

. Здесь DataSource установлен в aspx..cs file

rptTags.DataSource = new[] { new Datum { {"Count", 1} }, new Datum { {"Count", 2 } };

А вот привязка в aspx-файле

<asp:Repeater ID="rptTags" runat="server">
    <ItemTemplate>
        <%# (int)Eval("Count") > 
    </ItemTemplate>
</asp:Repeater>

Используя приведенный выше пример, мы получаем ошибку о том, что рассматриваемое свойство не существует, чтоИстина, но она также не существует в DataRow.Как я могу сделать так, чтобы он связывался как System.Data.DataRow?

Ответы [ 2 ]

1 голос
/ 15 февраля 2012

Я пришел этим утром свежим взглядом и провел несколько часов, просматривая .Net Framework с помощью ILSpy.Я наконец смог разгадать эту загадку и реализовать рабочее решение.Я перечислю вещи, которые я узнал, которые имеют отношение к решению, а затем подробно опишу мою реализацию.

  • Когда вы привязываете DataTable к Repeater, каждый RepeaterItem не привязывается к DataRow, как я ожидал,но для DataRowView.Это действительно не важно, за исключением того, что DataRowView реализует интерфейс ICustomTypeDescriptor, который нам нужен для реализации в нашем классе.
  • Хотя в документации MSDN говорится, что метод Eval использует отражение длявыполнить позднее связывание, и ваше выражение должно быть оценено как общедоступное свойство, это просто неверно.Оператор Eval использует метод GetProperties () в ICustomTypeDescriptor для оценки вашего выражения.

Имея это в виду, вот шаги, которые мне пришлось предпринять, чтобы создать свой собственный тип, который я мог бы динамически связать скак DataTable.

  1. Создайте свой собственный класс, который наследует от PropertyDescriptor.
  2. Реализация всех абстрактных членов PropertyDescriptor.Для динамического связывания наиболее важным является GetValue ().Здесь вы определяете, как получить значения из класса, к которому вы привязываетесь.
  3. В классе, к которому вы будете привязываться, наследуйте от CustomTypeDescriptor.Это универсальный класс, который реализует ICustomTypeDescriptor.
  4. Переопределяет метод GetProperties () CustomTypeDescriptor и возвращает список ваших PropertyDescriptors (созданных в шагах 1-2) для каждого значения, которое вы хотите связать с.
  5. Убедитесь, что в свойствах PropertyDescription установлено свойство Name.Это свойство .Net сравнивает ваше выражение Eval с тем, чтобы определить, какую PropertyDescription использовать при связывании.
  6. Установите ваш объект CustomTypeDescriptor (созданный в шагах 3-5) в качестве DataSource для WebControl и используйте Eval () динамически связываться с ним
0 голосов
/ 15 февраля 2012

Связываемый источник данных должен реализовывать либо IEnumerable, либо IListSource.

Что касается динамического аспекта: имейте в виду, что часть магии привязки данных происходит с помощью отражения.

...