Можно ли связать свойства сложного типа с сеткой данных? - PullRequest
19 голосов
/ 23 сентября 2008

Как мне связать следующий объект, Car, с видом сетки?

public class Car
{
   long Id {get; set;}
   Manufacturer Maker {get; set;}
}

public class Manufacturer
{
   long Id {get; set;}
   String Name {get; set;}
}

Примитивные типы связываются легко, но я не нашел способа что-либо показать для Maker. Я бы хотел, чтобы он отображал Имя производителя. Это вообще возможно?

Как бы это сделать? Должен ли я также хранить ManufacturerId в машине, а затем настроить lookupEditRepository со списком производителей?

Ответы [ 8 ]

26 голосов
/ 13 мая 2012

Ладно, ребята ... Этот вопрос был опубликован давно, но я только что нашел довольно хороший и простой способ сделать это, используя отражение в событии cell_formatting для получения вложенных свойств.

Идет так:

    private void Grid_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
    {

        DataGridView grid = (DataGridView)sender;
        DataGridViewRow row = grid.Rows[e.RowIndex];
        DataGridViewColumn col = grid.Columns[e.ColumnIndex];
        if (row.DataBoundItem != null && col.DataPropertyName.Contains("."))
        {
            string[] props = col.DataPropertyName.Split('.');
            PropertyInfo propInfo = row.DataBoundItem.GetType().GetProperty(props[0]);
            object val = propInfo.GetValue(row.DataBoundItem, null);
            for (int i = 1; i < props.Length; i++)
            {
                propInfo = val.GetType().GetProperty(props[i]);
                val = propInfo.GetValue(val, null);
            }
            e.Value = val;
        }
    }

И это все! Теперь вы можете использовать знакомый синтаксис «ParentProp.ChildProp.GrandChildProp» в DataPropertyName для вашего столбца.

12 голосов
/ 23 сентября 2008

Да, вы можете создать TypeDescriptionProvider для выполнения вложенного связывания. Вот подробный пример из блога MSDN:

http://blogs.msdn.com/msdnts/archive/2007/01/19/how-to-bind-a-datagridview-column-to-a-second-level-property-of-a-data-source.aspx

7 голосов
/ 24 сентября 2008

Способ, которым я подошел к этому в недавнем приложении, заключался в создании моих собственных классов DataGridViewColumn и DataGridViewCell, наследующих один из существующих, таких как DataGridViewTextBoxColumn и DataGridViewTextBoxCell.

В зависимости от типа ячейки, которую вы хотите, вы можете использовать другие, такие как Button, Checkbox, ComboBox и т. Д. Просто взгляните на типы, доступные в System.Windows.Forms.

Ячейки относятся к своим значениям как к объектам, поэтому вы можете передать свой класс Car в значение ячейки.

Переопределение SetValue и GetValue позволит вам иметь любую дополнительную логику, необходимую для обработки значения.

Например:

public class CarCell : System.Windows.Forms.DataGridViewTextBoxCell
{
    protected override object GetValue(int rowIndex)
    {
        Car car = base.GetValue(rowIndex) as Car;
        if (car != null)
        {
            return car.Maker.Name;
        }
        else
        {
            return "";
        }
    }
}

В классе столбцов главное, что вам нужно сделать, - установить CellTemplate в свой пользовательский класс ячеек.

public class CarColumn : System.Windows.Forms.DataGridViewTextBoxColumn
{
    public CarColumn(): base()
    {
        CarCell c = new CarCell();
        base.CellTemplate = c;
    }
}

Использование этих пользовательских столбцов / ячеек в DataGridView позволяет вам добавить множество дополнительных функций в ваш DataGridView.

Я использовал их для изменения отображаемого форматирования, переопределив GetFormattedValue, чтобы применить пользовательское форматирование к строковым значениям.

Я также сделал переопределение в Paint, чтобы можно было делать пользовательское выделение ячеек в зависимости от условий значения, изменяя ячейки Style.BackColor на то, что я хотел, основываясь на значении.

5 голосов
/ 23 сентября 2008
    public class Manufacturer
    {
       long Id {get; set;}
       String Name {get; set;}

       public override string ToString()
       {
          return Name;
       }
    }

Переопределить метод на строку.

2 голосов
/ 09 марта 2011

Вот еще один вариант, с которым я начал работать:

<asp:TemplateColumn
    HeaderText="Maker">
    <ItemTemplate>
          <%#Eval("Maker.Name")%>
    </ItemTemplate>
</asp:TemplateColumn>

Может быть, это специфично для ASP.NET 4.0, но работает как шарм!

2 голосов
/ 01 октября 2008

Если вы хотите представить конкретные вложенные свойства в качестве целей привязки, то ответ Бена Хоффштейна (http://blogs.msdn.com/msdnts/archive/2007/01/19/how-to-bind-a-datagridview-column-to-a-second-level-property-of-a-data-source.aspx) довольно хороший. Ссылочная статья немного туповата, но работает.

Если вы просто хотите связать столбец со сложным свойством (например, «Производитель») и переопределить логику рендеринга, то либо сделайте то, что рекомендовал ManiacXZ, либо просто создайте подкласс BoundField и предоставьте пользовательскую реализацию FormatDataValue (). Это похоже на переопределение ToString (); Вы получаете ссылку на объект и возвращаете строку, которую хотите отобразить в вашей сетке.

Примерно так:

public class ManufacturerField : BoundField
{
    protected override string FormatDataValue(object dataValue, bool encode)
    {
        var mfr = dataValue as Manufacturer;

        if (mfr != null)
        {
            return mfr.Name + " (ID " + mfr.Id + ")";
        }
        else
        {
            return base.FormatDataValue(dataValue, encode);
        }
    }
}

Просто добавьте ManufacturerField в свою сетку, указав «Производитель» в качестве поля данных, и все готово.

2 голосов
/ 23 сентября 2008

Просто используйте List и установите DataMember в строку «Maker.Name», а если вы хотите, чтобы DataKeyField использовал идентификатор автомобиля, просто установите для него «ID». 1005 *

dataGrid.DataSource = carList;
dataGrid.DataMember = "Maker.Name";
dataGrid.DataKeyField = "ID";
dataGrid.DataBind();

Я знаю, что работает в ретрансляторе, по крайней мере ...

1 голос
/ 02 июня 2009

Я предполагаю, что вы могли бы сделать следующее:

public class Car
{
    public long Id {get; set;}
    public Manufacturer Maker {private get; set;}

    public string ManufacturerName
    {
       get { return Maker != null ? Maker.Name : ""; }
    }
}

public class Manufacturer
{
   long Id {get; set;}
   String Name {get; set;}
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...