Accomplish gallery-type display with a Windows Forms data control and DataTable?

前端 未结 3 1613
粉色の甜心
粉色の甜心 2021-01-27 02:29

I have a datatable that looks like the following:

Room   Cook   Waiter  BG_Image
----------------------------------
201    Joe    Jim     Green.png
         


        
相关标签:
3条回答
  • 2021-01-27 03:00

    Cloning your design is not hard; and using some sort of DataBinding to your DataTable to display the data can be achieved with a little workaround.

    Things will get trickier, read: need more effort, when you want more than simply displaying the data. I will not go into that here.

    Here is a tiny example:

    The code below only lets your display the data. There is no provision for any of the advanced functionality you can get from DataBinding like navigation, editing, validation..

    The issue at hand really consists of three separate problems:

    • You want to use DataBinding to multiple records.
    • You want a free or tabular layout, not a row-orientated one.
    • The fields of a record should go into a freely laid out display object.

    For the latter there are many options going from a owner-drawn Panel subclass to a custom-made UserControl. Let's go for the latter as it is simple to code and easier to expand.

    For the second we can choose between several container controls. I'll go for a FlowLayoutPanel.

    But how can we use DataBinding? Even if we bind members of the UC we still don't get multi-record data-binding.

    The workaround uses the one Winforms control I can think of that provides multi-record data-binding: A DatGridView. But as it will only display a grid of cells with rows and columns, each cell holding one value, we won't let it display anything at all:

    DataGridView dataGridView1 = new DataGridView();
    DataTable DT = null;
    
    public Form1()
    {
        InitializeComponent();
        dataGridView1.DataSourceChanged += dataGridView1_DataSourceChanged;
    }
    

    As you can see the DGV is created strictly with the default values but not added to the Form, so it doesn't show.

    We only use its DataSource (after loading the DataTable, obvioulsy):

    private void button1_Click(object sender, EventArgs e)
    {
        dataGridView1.DataSource = DT;
    }
    

    When the DataSource changes we clear the FlowLayoutPanel we use to host the display controls and add one for each DataRow:

    private void dataGridView1_DataSourceChanged(object sender, EventArgs e)
    {
        DataTable dt = (DataTable)dataGridView1.DataSource;
        flowLayoutPanel1.Controls.Clear();
        foreach (DataRow row in dt.Rows)
        {
            UCBind ucb = new UCBind(row, imageList1);
            flowLayoutPanel1.Controls.Add(ucb);
        }
    }
    

    The FlowLayoutPanel makes life very easy; just make sure its size can hold the right number of display controls! But you could also add them to a TableLayoutPanel or even a simple Panel. For these you need to but also can determine all the layout details yourself.

    Now for the display control.

    I have created a UserControl UCBind and pass in a DataRow and an ImageList in the constructor. The code looks like this:

    public partial class UCBind : UserControl
    {
        ImageList imgList { get; set; }
    
        public UCBind()
        {
            InitializeComponent();
            DoubleBuffered = true;  // prevent flicker
        }
    
        public UCBind(DataRow row, ImageList imglist)
        {
            InitializeComponent();
            DoubleBuffered = true;  // prevent flicker
            if (row != null)
            {
                imgList = imglist;
                DisplayData(row);
            }
        }
    
        public void DisplayData(DataRow row)
        {
            lbl_field1.Text = row.Field<int>(0) + "";
            lbl_field2.Text = row.Field<string>(1);
            lbl_field3.Text = row.Field<string>(2);
            if (imgList != null) BackgroundImage = imgList.Images[row.Field<string>(3)];
    
        }
    }
    

    Obviously there is a little more going on in the designer code to style the UC and its fields:

    • Add three Labels
    • Dock each to the Top.
    • Set AutoSize = false.
    • Enlarge the Height
    • set their ForeColor to White.
    • Change the Fonts as needed.
    • Set TextAlignment to Left, Right & Right.
    • Set all BackColors to Transparent.
    • Set BackgroundImageLayout to Stretch.

    You will also want to set the Size to what you want.

    I have not included the designer genrated code as it tends to be rather long. Simply create the new UserControl class yourself, add the Labels, styling and the few lines of constructor code above..!

    And to make it rich you could try to add resizing code to make the FLP always fill with the right number of controls.

    Obviously the rounded corners and 3d borders will look best if you don't distort the image. I use an ImageList with suitable values for ColorDepth and ImageSize and load the three Images. Then I pass a reference to it to each UC I create.. The ImageList is added to the form and you can load the images into it right in the VS designer..:

    0 讨论(0)
  • 2021-01-27 03:08

    Here's some VB code to add an array of textboxes to a FlowLayoutPanel:

    Sub AddMany(cols As Integer, rows As Integer)
        Dim txt As TextBox
        FlowLayoutPanel1.FlowDirection = FlowDirection.LeftToRight
        FlowLayoutPanel1.AutoScroll = True
        For y As Integer = 0 To rows - 1
            For x As Integer = 0 To cols - 1
                If Not (x = 0 And y = 0) Then
                    txt = New TextBox
                    txt.Text = "txt_" & y & "_" & x
                    txt.Name = "txt_" & y & "_" & x
                    FlowLayoutPanel1.Controls.Add(txt)
                    AddHandler txt.KeyDown, AddressOf MoveKeyDown
                    AddHandler txt.DoubleClick, AddressOf ShowMeta
                End If
            Next
            FlowLayoutPanel1.SetFlowBreak(txt, True)
        Next
    End Sub
    

    Instead of simple TextBoxes you could add Buttons with images or PictureBoxes. You'd have to paint the text onto the images - or use a custom control.

    0 讨论(0)
  • 2021-01-27 03:12

    I'd say go for a 3rd party control library like devexpress (https://documentation.devexpress.com/#WindowsForms/CustomDocument3466) or telerik.

    It is really easy to build exactly the same output as your image using WPF. WPF controls are easy to host in a WinForms environment using an ElementHost (see https://dzone.com/articles/hosting-wpf-controls-winforms for an example or just google it)

    Hints for WPF: use a WrapPanel as container. See http://www.dotnetperls.com/wrappanel for an example.

    0 讨论(0)
提交回复
热议问题