Reputation:
I have a program that gets data from a MySQL Database and displays it to a DataGridView. Because each row is an app that can be downloaded, I want each row to be displayed in it's own little block. Here's a little sketch of what I want:
Each box shown is a row. Each section (Icon, app name, description, downloadbtn) is a column. Anyone know how to do this?
Upvotes: 1
Views: 260
Reputation: 54433
ListViews
don't support DataBinding
and while DataGridviews
do they only display a matrix of rows and columns, so they can't display row data side by side.
I suggest do away with your DataGridview
.
Instead you tie the data to a suitable other container which you fill with a UserControl
that display your data. An AutoScrolling
FlowLayoutPanel
is probably the best choice.
So you create a UserControl
, called, say DataBox
, add a few Labels
and the Button
and an extra constructor that can load the data from a DataTable.DataRow
.
Then you code a loading function that creates a new DataBox
for each row in the table and loads its fields into your Labels.
Then you call the function from all spots where the data change like maybe the RowChanged
event of the DataTable
..
Here is a minimal example class:
public delegate void ButtonClick(object sender, EventArgs e);
public partial class DataBox : UserControl
{
public DataRow row { get; set; }
public ButtonClick ButtonClick { private get; set; }
public DataBox()
{
InitializeComponent();
}
public DataBox(DataRow row)
{
InitializeComponent();
loadRow(row);
button1.GotFocus += (s, e) => { BackColor = Color.SkyBlue; };
button1.LostFocus += (s, e) => { BackColor = Color.Azure; };
}
public void loadRow(DataRow row_)
{
if (row_ == null || row_.ItemArray.Length < 3) return;
row = row_;
label1.Text = row.ItemArray[0].ToString();
label2.Text = row.ItemArray[1].ToString();
label3.Text = row.ItemArray[2].ToString();
}
private void button1_Click(object sender, EventArgs e)
{
if (ButtonClick != null) ButtonClick(sender, e);
}
}
When data change the display will refresh:
private void DT_RowChanged(object sender, DataRowChangeEventArgs e)
{
loadBoxes();
}
This is a loading function, which loads all rows in the table:
void loadBoxes()
{
List<DataBox> boxes = new List<DataBox>();
foreach (DataRow row in DT.Rows)
boxes.Add(new DataBox(row) { ButtonClick = boxButton_Click } );
flowLayoutPanel1.Controls.Clear();
flowLayoutPanel1.Controls.AddRange(boxes.ToArray());
boxes.Clear();
}
The Buttons
are calling a central click processing function in you form:
private void boxButton_Click(object sender, EventArgs e)
{
Button btn = sender as Button;
DataBox box = btn.Parent as DataBox;
if (box != null)
Console.WriteLine(box.rowID + " clicked");
}
But of course you may instead code their click right in the DataBox
class..
You may want to improve on a few other points, like updating single rows or making the Labels
send focus to the Button
, thus causing the BackColor
to show the 'selection'..
Upvotes: 2