как запрограммировать ListBox на мультистрочность?

312
19 декабря 2021, 16:50

Использую WinForms на .Net Compact Framework для Windows Mobile devices.

Появилась задача, для которой необходимо реализовать функционал мультистрочности для элемента ListBox. В нем есть строки, которые разделены __ - двумя нижними подчеркиваниями, Можно ли разделить эти строки на условно вторую, третью и т.д. если строчка выходит за пределы ListBox?. Если бы я не использовал .Net Compact Framework, то я бы воспользовался свойствами/событиями DrawMode и DrawItem, но этот фреймворк не поддерживает эти свойства.

Но можно их самому запрограммировать, мой уровень знаний для WinForms ставит меня в тупик, Кто-то может подсказать как правильно запрограммировать эту функциональность переноса строки, не создавая нового Item?

Answer 1

Нашел решение на EnSO:

using System;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            InitializeComboBox();
        }
        private ComboxBoxEx cbox1 = new ComboxBoxEx();
        private DataTable items = new DataTable();
        private void InitializeComboBox()
        {
            items.Columns.AddRange(new DataColumn[] { new DataColumn("id"), new DataColumn("name"), new DataColumn("address") });
            items.Rows.Add(new object[] { 0, "[Please choose an address]", "" });
            items.Rows.Add(new object[] { 1, "Country", "Country" });
            items.Rows.Add(new object[] { 2, "House name", "House name\nStreet name\nTown name\nPostcode\nCountry" });
            items.Rows.Add(new object[] { 3, "House name", "House name\nStreet name\nTown name\nPostcode\nCountry" });
            cbox1.Location = new Point(39, 20);
            cbox1.Size = new System.Drawing.Size(198, 21);
            cbox1.DrawMode = DrawMode.OwnerDrawVariable;
            cbox1.DrawItem += new DrawItemEventHandler(comboBox2_DrawItem);
            cbox1.MeasureItem += new MeasureItemEventHandler(comboBox2_MeasureItem);
            cbox1.SelectedIndexChanged += new EventHandler(comboBox2_SelectedIndexChanged);
            //cbox1.DropDownWidth = 250;
            //cbox1.DropDownHeight = 300;
            //cbox1.MaxDropDownItems = 6;
            this.Controls.Add(cbox1);
            cbox1.ValueMember = "id";
            cbox1.DisplayMember = "name";
            cbox1.DataSource = new BindingSource(items, null);
            //cbox1.SelectedIndex = -1;
        }
        private void comboBox2_MeasureItem(object sender, MeasureItemEventArgs e)
        {
            ComboxBoxEx cbox = (ComboxBoxEx)sender;
            DataRowView item = (DataRowView)cbox.Items[e.Index];
            string txt = item["address"].ToString();
            int height = Convert.ToInt32(e.Graphics.MeasureString(txt, cbox.Font).Height);
            e.ItemHeight = height + 4;
            e.ItemWidth = cbox.DropDownWidth;
            cbox.ItemHeights.Add(e.ItemHeight);
        }
        private void comboBox2_DrawItem(object sender, DrawItemEventArgs e)
        {
            ComboxBoxEx cbox = (ComboxBoxEx)sender;
            DataRowView item = (DataRowView)cbox.Items[e.Index];
            string txt = item["address"].ToString();
            e.DrawBackground();
            e.Graphics.DrawString(txt, cbox.Font, System.Drawing.Brushes.Black, new RectangleF(e.Bounds.X + 2, e.Bounds.Y + 2, e.Bounds.Width, e.Bounds.Height));
            e.Graphics.DrawLine(new Pen(Color.LightGray), e.Bounds.X, e.Bounds.Top + e.Bounds.Height - 1, e.Bounds.Width, e.Bounds.Top + e.Bounds.Height - 1);
            e.DrawFocusRectangle();
        }
        private void comboBox2_SelectedIndexChanged(object sender, EventArgs e)
        {
            ComboxBoxEx cbox = (ComboxBoxEx)sender;
            if (cbox.SelectedItem == null) return;
            DataRowView item = (DataRowView)cbox.SelectedItem;
            //label1.Text = item["id"].ToString();
        }
    }
}

Нужно создать наследника ComboBox'а, так как автор ответа утверждает, что в этом случае возникнет проблема с определением размеров:

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Collections.Generic;
namespace WindowsFormsApplication1
{
    public partial class ComboxBoxEx : ComboBox
    {
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);
        [DllImport("user32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags);
        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int Left;        // x position of upper-left corner 
            public int Top;         // y position of upper-left corner 
            public int Right;       // x position of lower-right corner 
            public int Bottom;      // y position of lower-right corner 
        }
        public const int SWP_NOZORDER = 0x0004;
        public const int SWP_NOACTIVATE = 0x0010;
        public const int SWP_FRAMECHANGED = 0x0020;
        public const int SWP_NOOWNERZORDER = 0x0200;
        public const int WM_CTLCOLORLISTBOX = 0x0134;
        private int _hwndDropDown = 0;
        internal List<int> ItemHeights = new List<int>();
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_CTLCOLORLISTBOX)
            {
                if (_hwndDropDown == 0)
                {
                    _hwndDropDown = m.LParam.ToInt32();
                    RECT r;
                    GetWindowRect((IntPtr)_hwndDropDown, out r);
                    int newHeight = 0;
                    int n = (Items.Count > MaxDropDownItems) ? MaxDropDownItems : Items.Count;
                    for (int i = 0; i < n; i++)
                    {
                        newHeight += ItemHeights[i];
                    }
                    newHeight += 5; //to stop scrollbars showing
                    SetWindowPos((IntPtr)_hwndDropDown, IntPtr.Zero,
                        r.Left,
                                 r.Top,
                                 DropDownWidth,
                                 newHeight,
                                 SWP_FRAMECHANGED |
                                     SWP_NOACTIVATE |
                                     SWP_NOZORDER |
                                     SWP_NOOWNERZORDER);
                }
            }
            base.WndProc(ref m);
        }
        protected override void OnDropDownClosed(EventArgs e)
        {
            _hwndDropDown = 0;
            base.OnDropDownClosed(e);
        }
    }
}
READ ALSO
Можно в terrain.terrainData.treeInstances поместить не деревья?

Можно в terrain.terrainData.treeInstances поместить не деревья?

Мне надо создать кисть в которой будут камни, столбы, кусты и прочие элементы окружающей средыЯ купил кисть Prefab Brush

96
Таблица Шульте. Нужно довести до ума

Таблица Шульте. Нужно довести до ума

Таблица Шульте - таблица случайно расположенных чисел, обычно размером 5x5 элементов и обычно состоит из цифр и буквПример: https://cepia

232
Программа добавленная в автозагрузку не запускаеться C#

Программа добавленная в автозагрузку не запускаеться C#

Здравствуйте кто сможет помочь мне нужно чтобы программа сама себя кидала в автозагрузкупробовал много что не помогало например:

130
Порядок foreach

Порядок foreach

Хотел сделать вызов определенного forech в зависимости от того, какой игрок ходит, но при любом случае, срабатывает только первый, не смотря...

189