2015-03-12 9 views
1

Мне нужно реализовать какой-то эффект аккордеона в Windows Form DataGridView. Когда пользователь выбирает строку, строка расширяется, чтобы отобразить дополнительную информацию и, если возможно, некоторые кнопки или другие элементы управления. Проблема в том, что я не знаю, как это сделать. Я попытался найти в Интернете, но я не нашел ничего, что могло бы привести меня в правильном направлении при создании этого. Надеюсь, кто-нибудь скажет мне, как это сделать? (не обязательно должен быть образцом кода)Аккордеон в Windows Forms DataGridView

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

Я думал о настройке высоты столбцов и переопределении метода OnPaint. Мне нужно отобразить только текст в первой версии. Если это возможно, это было бы здорово. Я знаю, что в будущем мне нужно будет поместить некоторые кнопки или другие элементы управления, чтобы делать разные вещи с выбранным элементом. Если это очень сложно достичь, я сейчас пропущу эту часть. Я знаю, что я мог бы использовать всплывающие подсказки для текста и иметь столбцы кнопок и т. Д., Но в моем случае мне нужно сделать это как аккордеон.

DataGridView with accordion mockup

С наилучшими пожеланиями Hans Фрезерная ...

+0

посмотрите http://www.codeproject.com/Tips/835501/Master-Detail-Datagridview – ASh

+0

Я обновил свой ответ, чтобы включить код для действия кнопки. – TaW

ответ

5

Это не очень трудно сделать. Лучшим подходом было бы создание выделенного UserControl и наложение его в нужное место.

Чтобы освободить место для этого, просто измените строку Height Row, отслеживая строку, чтобы вы могли вернуть ее, когда она теряет выделение.

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

UserControl может иметь функцию displayRowData(DataGridViewRow row) которые вы могли бы Вызов индикации полей интересующих вас в его Labels и т.д ..

вы также должны иметь план о том, как Buttons взаимодействует с DataGridView ..

Если вы хотите только один ряд будет расширен в время, вы можете создать UC спереди, сделать DGV его Parent и спрятать его. Позже пользовательское взаимодействие, например, щелчок по строке или определенной ячейке, вы переместите его в правый ряд и покажите его.

Если можно расширить несколько строк, вам нужно будет создать несколько UCs и сохранить их отслеживание в List ..

Вот минимальный пример, который поможет вам ..:

enter image description here

int normalRowHeight = -1; 
UcRowDisplay display = new UcRowDisplay(); 
DataGridViewRow selectedRow = null; 

public Form1() 
{ 
    InitializeComponent(); 

    // create one display object 
    display = new UcRowDisplay(); 
    display.Visible = false; 
    display.Parent = DGV; 
    display.button1Action = someAction; 
} 

После наполнили DGV

// store the normal row height 
    normalRowHeight = DGV.Rows[0].Height; 

Вы должны по крайней мере, эти события:

private void DGV_SelectionChanged(object sender, EventArgs e) 
{ 
    if (selectedRow != null) selectedRow.Height = normalRowHeight; 
    if (DGV.SelectedRows.Count <= 0) 
    { 
     selectedRow = null; 
     display.Hide(); 
     return; 
    } 
    // assuming multiselect = false 
    selectedRow = DGV.SelectedRows[0]; 
    // assuming ColumnHeader show with the same height as the rows 
    int y = (selectedRow.Index + 1) * normalRowHeight; 
    display.Location = new Point(1, y); 
    // filling out the whole width of the DGV. 
    // maybe you need more, if the DGV is scrolling horizontally 
    // or less if you show a vertical scrollbar.. 
    display.Width = DGV.ClientSize.Width; 
    // make room for the display object 
    selectedRow.Height = display.Height; 
    // tell it to display our row data 
    display.displayRowData(selectedRow); 
    // show the display 
    display.Show(); 
} 

private void DGV_ColumnWidthChanged(object sender, DataGridViewColumnEventArgs e) 
{ 
    // enforce refresh on the display 
    display.Refresh(); 
} 

Вот тест действие запускается с помощью кнопки в дисплейный объект:

public void someAction(DataGridViewRow row) 
{ 
    Console.WriteLine(row.Index + " " + row.Cells[2].Value.ToString()); 
} 

И, конечно, вам нужен UserControl. Вот простой один, с двумя метками, одна кнопка и один дополнительный ярлык, чтобы закрыть экран:

public partial class UcRowDisplay : UserControl 
{ 
    public UcRowDisplay() 
    { 
     InitializeComponent(); 
    } 

    public delegate void someActionDelegate(DataGridViewRow row); 
    public someActionDelegate button1Action { get; set; } 
    DataGridViewRow myRow = null; 

    public void displayRowData(DataGridViewRow row) 
    { 
     myRow = row; 
     label1.Text = row.Cells[1].Value.ToString(); 
     label2.Text = row.Cells[0].Value.ToString(); 
     rowDisplayBtn1.Text = row.Cells[2].Value.ToString(); 
    } 

    private void rowDisplayBtn1_Click(object sender, EventArgs e) 
    { 
     button1Action(myRow); 
    } 

    private void label_X_Click(object sender, EventArgs e) 
    { 
     myRow.Selected = false; 
     this.Hide(); 
    } 
} 

Он содержит tthree Labels и Button. В конструкторе это выглядит следующим образом:

enter image description here

Обратите внимание, что для того, чтобы сделать его немного легче на меня изменили DGV к

  • нет RowHeader; измените местоположение, если оно у вас есть.
  • предполагал, что заголовок столбца имеет ту же высоту, что и строка.
  • все (обычные) ряды имеют одинаковые высоты.
  • установить DGV в MULTISELECT = ложь и только для чтения

Update

Вот быстрый пример для прокрутки:

private void DGV_Scroll(object sender, ScrollEventArgs e) 
{ 
    DGV.PerformLayout(); 
    var ccr = DGV.GetCellDisplayRectangle(0, selectedRow.Index, true); 
    display.Top = ccr.Top + normalRowHeight; // ** 
    display.Visible = (ccr.Top >= 0 && ccr.Height > 0); 
} 

Это (**) принимает, что выбранная строка должна оставаться видимой. Тот же расчет должен произойти в событии SelectionChanged! Это зависит от вас, чтобы решить, что должно произойти при возникновении горизонтальной прокрутки.

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

+0

Спасибо, что так много. Это именно то, что мне нужно для начала. – nivs1978

+0

BTW, я только заметил, что ваш макет показывает расширенный ряд, а также область расширения. Для этого вам нужно было бы: 1) сделать строку еще выше, 2) вычислить uc, чтобы отобразить немного ниже; 3) убедитесь, что ячейки строки выравнивают содержимое до вершины. – TaW